I generated ac# class using xsd.exe with this xml file:
<?xml version="1.0" encoding="UTF-8"?>
<Mary>
<Frank>
<Joe>
<Susan>
<Stuff>data</Stuff>
</Susan>
<Susan>
<Stuff>data</Stuff>
</Susan>
</Joe>
<Joe>
<Susan>
<Stuff>data</Stuff>
</Susan>
<Susan>
<Stuff>data</Stuff>
</Susan>
</Joe>
</Frank>
</Mary>
The C# class that was generated can be viewed here.
I can initialize the object with data:
var susan = new MaryFrankJoeSusan(){Stuff = "my data"};
var frank = new MaryFrank(){Joe = new MaryFrankJoeSusan[1][]};
frank.Joe[0] = new MaryFrankJoeSusan[1]{susan};
var mary = new Mary { Items = new MaryFrank[1] { frank } };
I'm using the following to serialize it to disk:
var serializer = new XmlSerializer(typeof(Mary));
using (Stream stream = new FileStream(@"C:\out.xml", FileMode.Create))
{
var settings = new XmlWriterSettings { Indent = true, NewLineOnAttributes = true, OmitXmlDeclaration = true};
using (XmlWriter writer = new XmlTextWriter(stream, Encoding.Unicode))
{
serializer.Serialize(writer, mary);
writer.Close();
}
}
However I am get the following error when the serializer is initialized:
error CS0030: Cannot convert type 'MaryFrankJoeSusan[]' to 'MaryFrankJoeSusan'
How do I serialize the entire Mary object to disk?
Something is off with those generated classes.
The problem is happening because MaryFrank.Joe
is declared as a two-dimensional array of MaryFrankJoeSusan
objects, but it is decorated with a XmlArrayItemAttribute
which is telling the serializer that each item of that 2D array are of type MaryFrankJoeSusan
when they are of course MaryFrankJoeSusan[]
.
If you change this line in the generated classes:
[System.Xml.Serialization.XmlArrayItemAttribute("Susan", typeof(MaryFrankJoeSusan),
Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=false)]
to this:
[System.Xml.Serialization.XmlArrayItemAttribute("Susan", typeof(MaryFrankJoeSusan[]),
Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=false)]
then it will serialize without error. However, you won't get the results you are looking for. Instead of this:
<Mary>
<Frank>
<Joe>
<Susan>
<Stuff>my data</Stuff>
</Susan>
</Joe>
</Frank>
</Mary>
you will get this (note the extra MaryFrankJoeSusan
tag):
<Mary>
<Frank>
<Joe>
<Susan>
<MaryFrankJoeSusan>
<Stuff>my data</Stuff>
</MaryFrankJoeSusan>
</Susan>
</Joe>
</Frank>
</Mary>
The real problem seems to be that the xsd.exe
tool has generated the class structure incorrectly to begin with. It is not creating a class in the heirarchy to represent Joe, but is instead trying to combine Joe and Susan together, which doesn't really work here.
I ran your original XML from the question through the tool to generate an XSD schema, and I got this:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="Mary" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="Mary" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="Frank">
<xs:complexType>
<xs:sequence>
<xs:element name="Joe" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="Susan" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="Stuff" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
which looks OK to me. Then I took that same schema and ran it through the tool again to generate C# classes. I would have expected to get something similar to this:
[Serializable]
[XmlRoot(Namespace = "", ElementName = "Mary")]
public class Mary
{
[XmlElement("Frank")]
public Frank[] Frank { get; set; }
}
[Serializable]
public class Frank
{
[XmlElement("Joe")]
public Joe[] Joe { get; set; }
}
[Serializable]
public class Joe
{
[XmlElement("Susan")]
public Susan[] Susan { get; set; }
}
[Serializable]
public class Susan
{
[XmlElement("Stuff")]
public string Stuff { get; set; }
}
but instead I got the same broken classes that you linked in the question. So it looks like a bug in the xsd tool to me.
To get it to work, you can either use the hand-coded classes I made above, changing your initialization code to this:
var susan = new Susan { Stuff = "my data" };
var joe = new Joe { Susan = new Susan[] { susan } };
var frank = new Frank { Joe = new Joe[] { joe } };
var mary = new Mary { Frank = new Frank[] { frank } };
--OR--
another alternative is to alter the xsd. Replace the xs:sequence
indicators for Frank
and Joe
elements with xs:choice
instead, like this:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="Mary" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="Mary" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="Frank">
<xs:complexType>
<xs:choice> <!-- was xs:sequence -->
<xs:element name="Joe" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:choice> <!-- was xs:sequence -->
<xs:element name="Susan" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="Stuff" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice> <!-- was /xs:sequence -->
</xs:complexType>
</xs:element>
</xs:choice> <!-- was /xs:sequence -->
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
With this schema, the generated classes come out much better: there is a class to represent Joe now. (I've simplified the generated code here and removed some of the attributes for brevity):
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=false)]
public partial class Mary {
[System.Xml.Serialization.XmlElementAttribute("Frank", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public MaryFrank[] Items { get; set; }
}
[System.SerializableAttribute()]
public partial class MaryFrank {
[System.Xml.Serialization.XmlElementAttribute("Joe", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public MaryFrankJoe[] Items { get; set; }
}
[System.SerializableAttribute()]
public partial class MaryFrankJoe {
[System.Xml.Serialization.XmlElementAttribute("Susan", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public MaryFrankJoeSusan[] Items { get; set; }
}
[System.SerializableAttribute()]
public partial class MaryFrankJoeSusan {
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string Stuff { get; set; }
}
The setup code then becomes:
var susan = new MaryFrankJoeSusan() { Stuff = "my data" };
var joe = new MaryFrankJoe() { Items = new MaryFrankJoeSusan[] { susan } };
var frank = new MaryFrank() { Items = new MaryFrankJoe[] { joe } };
var mary = new Mary { Items = new MaryFrank[] { frank } };
And we get the expected output:
<?xml version="1.0" encoding="utf-16"?>
<Mary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Frank>
<Joe>
<Susan>
<Stuff>my data</Stuff>
</Susan>
</Joe>
</Frank>
</Mary>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.