.NET Forum / .NET Framework / XML / March 2007
Serializing Class with Unqualified Root Element and Default Namespace attribute
|
|
Thread rating:  |
Mark Olbert - 12 Mar 2007 01:04 GMT I'm trying to serialize (using XmlSerializer.Serialize) a class that I generated from an XSD schema using XSD.EXE /c.
The problem I'm running into is that the root element needs to be unqualified, and the default namespace needs to be included on it as an attribute. The schema I'm using is this:
<xs:schema xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:html="http://www.w3.org/TR/REC-html40" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:c="urn:schemas-microsoft-com:office:component" attributeFormDefault="unqualified" targetNamespace="urn:schemas-microsoft-com:office:spreadsheet" elementFormDefault="unqualified"> <xs:import namespace="urn:schemas-microsoft-com:office:office" /> <xs:import namespace="urn:schemas-microsoft-com:office:excel" /> <xs:import namespace="urn:schemas-microsoft-com:office:component" /> <xs:element name="Workbook">... <xs:complexType> <xs:sequence> <xs:element ref="o:DocumentProperties" /> <xs:element ref="o:OfficeDocumentSettings" /> <xs:element ref="x:ExcelWorkbook" />
But when I use Serialize() I get this:
<?xml version="1.0" encoding="utf-8"?> <ss:Workbook xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:c="urn:schemas-microsoft-com:office:component" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">...
Which is close, but not close enough.
I tried specifying the default namespace in the call to Serialize(), but it didn't have any effect, on either the qualification on the Workspace node or the lack of the xmlns attribute on the node.
- Mark
Specifically, I need this:
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:c="urn:schemas-microsoft-com:office:component" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">
Martin Honnen - 12 Mar 2007 13:11 GMT > But when I use Serialize() I get this: > [quoted text clipped - 5 lines] > > Which is close, but not close enough.
> Specifically, I need this: > [quoted text clipped - 3 lines] > xmlns:c="urn:schemas-microsoft-com:office:component" > xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"> Semantically there is no difference between the two snippets, it does not matter in terms of XML and namespaces whether a namespace is used as the default namespace or with a prefix.
Can you show us the relevant C# or VB.NET class definition of the objects you serialize? There are attributes that set the namespace and the Serialize method has a third argument that maps prefixes to namespace URI so this class
[XmlRoot(Namespace = "urn:schemas-microsoft-com:office:spreadsheet", ElementName = "Workbook")] public class Foo { public Foo() { } }
with this code
Foo foo = new Foo(); XmlSerializer serializer = new XmlSerializer(typeof(Foo)); serializer.Serialize(Console.Out, foo);
serializes as
<Workbook xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="urn:schemas-microsoft-com:office:spreadsheet" />
while using this code
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces(); namespaces.Add("ss", "urn:schemas-microsoft-com:office:spreadsheet"); serializer.Serialize(Console.Out, foo, namespaces);
it serializes as
<ss:Workbook xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" />
 Signature Martin Honnen --- MVP XML http://JavaScript.FAQTs.com/
Mark Olbert - 12 Mar 2007 17:06 GMT Martin,
>Semantically there is no difference between the two snippets, it does not matter in terms of XML and namespaces whether a namespace is used as >the default namespace or with a prefix. Unfortunately, it appears to matter a great deal to Microsoft Excel. In testing on both Excel XP and Excel 2007, not having that xmlns="..." attribute prevents the file from being parsed. Personally, and not knowing much about XML, I think having two attributes that point at the same namespace (i.e., xmlns="..." and xmlns:ss="<same>") strikes me as weird...but apparently not to the folks who wrote Excel :).
>Can you show us the relevant C# or VB.NET class definition of the objects you serialize? There are attributes that set the namespace and >the Serialize method has a third argument that maps prefixes to namespace URI so this class [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.42")] [System.SerializableAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)] [System.Xml.Serialization.XmlRootAttribute(Namespace="urn:schemas-microsoft-com:office:spreadsheet", IsNullable=false)] public partial class Workbook { }
and
XmlSerializer serializer = new XmlSerializer(typeof(Workbook));
XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); ns.Add("x", "urn:schemas-microsoft-com:office:excel"); ns.Add("c", "urn:schemas-microsoft-com:office:component"); ns.Add("html", "http://www.w3.org/TR/REC-html40"); ns.Add("ss", "urn:schemas-microsoft-com:office:spreadsheet");
serializer.Serialize(tw, this, ns); // this is a Workbook object
generates:
<?xml version="1.0" encoding="utf-8"?> <ss:Workbook xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:html="http://www.w3.org/TR/REC-html40" xmlns:c="urn:schemas-microsoft-com:office:component" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"> <Worksheet ss:Name="Sheet1">
which doesn't work because the default xmlns tag is missing. Not adding the "ss" namespace to namespaces generates:
<?xml version="1.0" encoding="utf-8"?> <Workbook xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:html="http://www.w3.org/TR/REC-html40" xmlns:c="urn:schemas-microsoft-com:office:component" xmlns="urn:schemas-microsoft-com:office:spreadsheet"> <Worksheet d2p1:Name="Sheet1" xmlns:d2p1="urn:schemas-microsoft-com:office:spreadsheet" xmlns="">
which doesn't work because the Worksheet element redefines the default namespace to "". FYI, the Worksheet class definition is as follows:
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.42")] [System.SerializableAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:schemas-microsoft-com:office:spreadsheet")] public partial class WorkbookWorksheet { }
Adding the named tag ElementName="Workbook" to the XmlRootAttribute while not adding the ss namespace to the serializer generates
<?xml version="1.0" encoding="utf-8"?> <Workbook xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:html="http://www.w3.org/TR/REC-html40" xmlns:c="urn:schemas-microsoft-com:office:component" xmlns="urn:schemas-microsoft-com:office:spreadsheet"> <Worksheet d2p1:Name="Sheet1" xmlns:d2p1="urn:schemas-microsoft-com:office:spreadsheet" xmlns="">
which suppresses the ss: prefix on the Workbook node, but still has the problem of the Worksheet node redefining xmlns.
Adding the Namespace= parameter to the XmlTypeAttribute on WorkbookWorksheet:
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.42")] [System.SerializableAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "urn:schemas-microsoft-com:office:spreadsheet")] public partial class WorkbookWorksheet { }
generates
<?xml version="1.0" encoding="utf-8"?> <Workbook xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:html="http://www.w3.org/TR/REC-html40" xmlns:c="urn:schemas-microsoft-com:office:component" xmlns="urn:schemas-microsoft-com:office:spreadsheet"> <Worksheet d2p1:Name="Sheet1" xmlns:d2p1="urn:schemas-microsoft-com:office:spreadsheet" xmlns="">
again with the redefinition of the default namespace on the Worksheet node.
The schema where Workbook and Worksheet are defined looks like this (some hopefully unrelated details left out for brevity):
<?xml version="1.0" encoding="utf-8"?> <xs:schema xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:html="http://www.w3.org/TR/REC-html40" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:c="urn:schemas-microsoft-com:office:component" attributeFormDefault="unqualified" targetNamespace="urn:schemas-microsoft-com:office:spreadsheet" elementFormDefault="unqualified"> <xs:import namespace="urn:schemas-microsoft-com:office:office" /> <xs:import namespace="urn:schemas-microsoft-com:office:excel" /> <xs:import namespace="urn:schemas-microsoft-com:office:component" /> <xs:element name="Workbook"> <xs:complexType> <xs:sequence> <xs:element name="Styles"> </xs:element> <xs:element maxOccurs="unbounded" name="Worksheet"> <xs:complexType> <xs:sequence> </xs:sequence> <xs:attribute ref="ss:Name" use="required" /> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> ...
I appreciate your help, and look forward to other suggestions.
- Mark
Martin Honnen - 12 Mar 2007 18:31 GMT > The schema where Workbook and Worksheet are defined looks like this (some hopefully unrelated details left out for brevity): > [quoted text clipped - 3 lines] > xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:c="urn:schemas-microsoft-com:office:component" attributeFormDefault="unqualified" > targetNamespace="urn:schemas-microsoft-com:office:spreadsheet" elementFormDefault="unqualified"> Why is elementFormDefault set to unqualified? The MS reference schema for Office 2003 sets that to qualified.
 Signature Martin Honnen --- MVP XML http://JavaScript.FAQTs.com/
Mark Olbert - 12 Mar 2007 20:42 GMT Martin,
That schema was generated by having VS2005 generate a schema off of an Excel XP XML file. In the Excel XP XML file the element names are unqualified (I just double-checked that).
I don't know why that would've changed between Excel XP and Excel 2003.
Interestingly, changing the element form to qualified solved the problem. The generated XML file now looks like:
<?xml version="1.0" encoding="utf-8"?> <ss:Workbook xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:html="http://www.w3.org/TR/REC-html40" xmlns:c="urn:schemas-microsoft-com:office:component" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"> <ss:Worksheet ss:Name="Sheet1"> <ss:Table> <ss:Row ss:Index="1"> <ss:Cell ss:Index="1"> <ss:Data ss:Type="String">Ralphie</ss:Data> </ss:Cell> </ss:Row> <ss:Row ss:Index="4"> <ss:Cell ss:Index="4"> <ss:Data ss:Type="String">Joanie</ss:Data> </ss:Cell> </ss:Row> </ss:Table> </ss:Worksheet> </ss:Workbook>
which Excel 2007 (I just upgraded, so I no longer have Excel XP to test with) is happy to load as an Excel file.
So the problem's solved (at least for now). Thank you!
I double-checked the file I used to generate the schema to see if it would load in Excel 2007. It does, without a hitch. Here's what it looks like (edited for brevity):
<?xml version="1.0"?> <Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40"> <Worksheet ss:Name="Sheet1"> <Table ss:ExpandedColumnCount="4" ss:ExpandedRowCount="6" x:FullColumns="1" x:FullRows="1" ss:DefaultColumnWidth="60" ss:DefaultRowHeight="15"> <Row ss:AutoFitHeight="0"> <Cell><Data ss:Type="Number">1</Data></Cell> </Row> <Row ss:AutoFitHeight="0"> <Cell><Data ss:Type="Number">2</Data></Cell> </Row> <Row ss:AutoFitHeight="0"/> <Row ss:AutoFitHeight="0"> <Cell ss:Index="2"><Data ss:Type="String">a</Data></Cell> </Row> <Row ss:AutoFitHeight="0"/> <Row ss:AutoFitHeight="0"> <Cell ss:Index="4"><Data ss:Type="String">c</Data></Cell> </Row> </Table> </Worksheet> </Workbook>
I still wish I understood >>why<< it was solved, though, and why Excel XP generated an XML file with unqualified element names. It looks like, if the xmlns attribute is specified on the root node you don't need to qualify the element names, but if it isn't, you have to. Since I haven't been able to find a way to get the xmlns attribute added to the root node when I generate a file, I have to qualify the element names.
Then again, if I had a dollar for every XML/XSD/namespace issue I didn't understand, I'd be filthy rich.
- Mark
>> The schema where Workbook and Worksheet are defined looks like this (some hopefully unrelated details left out for brevity): >> [quoted text clipped - 6 lines] >Why is elementFormDefault set to unqualified? The MS reference schema >for Office 2003 sets that to qualified. Martin Honnen - 13 Mar 2007 13:52 GMT > I double-checked the file I used to generate the schema to see if it would load in Excel 2007. It does, without a hitch. Here's what > it looks like (edited for brevity): [quoted text clipped - 6 lines] > xmlns:html="http://www.w3.org/TR/REC-html40"> > <Worksheet ss:Name="Sheet1"> You misunderstand what elementFormDefault="unqualified" means. In that sample both elements, the Workbook element, and the Worksheet element, are in the namespace urn:schemas-microsoft-com:office:spreadsheet and a schema modelling that needs targetNamespace="urn:schemas-microsoft-com:office:spreadsheet" and elementFormDefault="qualified" . The schema you had with a targetNamespace="urn:schemas-microsoft-com:office:spreadsheet" but with elementFormDefault="unqualified" describes a Workbook element in the targetNamespace where child elements like Worksheet are in no namespace, hence the xmlns="" you got on that element.
 Signature Martin Honnen --- MVP XML http://JavaScript.FAQTs.com/
WenYuan Wang - 15 Mar 2007 12:49 GMT Hi Mark,
Additionally, XML namespaces is used to provide a simple method for qualifying element and attribute names used in XML documents.
For example: <Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40"> <Worksheet ss:Name="Sheet1">
"urn:schemas-microsoft-com:office:spreadsheet' is the default namespace for both <Workbook> and <WorkSheet> element.
But if you have many <WorkBook> elements with the different meaning in XML document, then how do you distinguish these <WorkBook> elements? Namespace can help you in this scenario.
< Workbook xmlns="namespace1"> ..< Worksheet > .....< Workbook xmlns="namespace2"> ........ .....</WorkBook> ..</ Worksheet > </ Workbook>
You can distinguish the root <Workbook> element by namespace "namespace1" and node <Workbook\Worksheet\Workbook> by namespace "namespace2".
Hope this will help you understand namespace.
You can get more detailed information by the following document. http://www.w3.org/TR/REC-xml-names/ [Namespaces in XML 1.0 (Second Edition)]
Have a great day, Sincerley, Wen Yuan
WenYuan Wang - 19 Mar 2007 15:47 GMT Hi Martin,
Just want to check whether you have met any further issue? Please feel free to update here. I'm glad to assist you.
Have a great day, Sincerely, Wen Yuan
WenYuan Wang - 12 Mar 2007 13:27 GMT Hi Mark
According to your description, what you need is the root element should be unqualified. If I have misunderstood anything here, please feel free to let me know.
The XSD schema which you posted in newsgroup is fine.
It seems like you Serialize the WorkBook class conjunction with XmlSerializerNamespaces. Public void Serialize (XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces) Would you please past some code snippet about how did you serialize the WorkBook Class?
As far as I know, there are two ways you can use to serialize the root element as unqualified. Senaro 1: Stream writer = new FileStream("Workbook.xml", FileMode.Create); XmlSerializerNamespaces xsnx = new XmlSerializerNamespaces(); xsnx.Add("", " urn:schemas-microsoft-com:office:spreadsheet"); xsns.Add(...); // other namespaces XmlSerializer serializer = new XmlSerializer(typeof(Workbook)); serializer.Serialize(writer, objWorkbook, xsnx);
Senaro 2: Stream writer = new FileStream("Workbook.xml", FileMode.Create); XmlSerializer serializer = new XmlSerializer(typeof(Workbook)); serializer.Serialize(writer, objWorkbook);
Hope this helps. Sincerely, Wen Yuan
Mark Olbert - 12 Mar 2007 17:07 GMT Wen Yuan,
Please see my reply to Martin. I tried your suggestions, but they don't solve the problem.
- Mark
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|