Reputation: 136
I am trying to create a waypoint generator using windows forms, that allows a user to create waypoint & path data via a GUI & output the data to an XML file. I've chosen to take advantage of the built in c# XML serialization feature, but have been unable to format the XML output in the way required by the client.
A stripped version of the waypoint data object would look something like the following:
// Waypoint data class
[XmlRoot("RootNode")]
public class WaypointProjectData
{
[XmlElement("Map")] // Also tried to use XmlElementAttribute,
[XmlAttribute("file")] // XmlAttributeAttribute, and many variations
// of these qualifiers, with no success
public string m_szMapImageFileName;
[XmlAttribute("width")]
public int m_iWidth;
[XmlAttribute("height")]
public int m_iHeight;
[XmlArray("Nodes")]
public ArrayList m_aoNodes;
WaypointProjectData()
{
m_szMapImageFileName = "map.png";
m_aoNodes = new ArrayList();
}
}
The client requires that the XML output conforms with the following layout/format:
<RootNode>
<Map file="map.png" width="100" height="100" />
<OtherData var="variable" data="10" />
<Nodes>
<Node x="10" y="30" />
<Node x="30" y="20" /> // etc...
</Nodes>
</RootNode>
Some clear examples on how to do this using c# xml serialization would be very helpful. Thanks!
Upvotes: 3
Views: 673
Reputation: 12778
When I have to serialize something in a specific Xml format like this, I start with a schema (inferred if necessary, hand-crafted if known). Then I use the VS xsd tool to create the serialization classes (and yes, I know xsd can be used for the inferring schema part—I just never bother with it for that purpose).
So if you have an xsd file like this one created from your example (note that I specified data types as much as possible—this helps the xsd tool to use the appropriate types for properties):
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="RootNode">
<xs:complexType>
<xs:sequence>
<xs:element name="Map">
<xs:complexType>
<xs:attribute name="file" type="xs:string"/>
<xs:attribute name="width" type="xs:decimal"/>
<xs:attribute name="height" type="xs:decimal"/>
</xs:complexType>
</xs:element>
<xs:element name="OtherData">
<xs:complexType>
<xs:attribute name="var" type="xs:string"/>
<xs:attribute name="data" type="xs:decimal"/>
</xs:complexType>
</xs:element>
<xs:element name="Nodes" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="Node" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="x" type="xs:decimal"/>
<xs:attribute name="y" type="xs:decimal"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
If you name this Root.xsd, then you can go to the VS command line and run
xsd Root.xsd /c /n:myProject.Xml
That'll create a class file (named Root.cs because that's the default when processing Root.xsd) that contains objects you can easily plug into .Net to serialize and deserialize the XML. Note that I specified the namespace the classes will have ("/n:myProject.Xml"). I prefer to control that namespace, but defaults are usually fine for the rest. Further, the tool creates partial classes, so if you want custom property accessors, you're fine to add them in a separate file that won't get creamed if you need to run the tool again.
Another tip, I create a text file in my project with the name "<xsd name> xsd Command Line.txt". That way I just have to paste that into the VS command line and don't have to remember everything else I used.
Upvotes: 1
Reputation: 20320
As soon as you go off the beaten track serialisation is a huge PIA. You need something to mark up as map, probably OtherData as well, so that means you need a class or struct that corresponds to the node. e.g. WaypointProejctdata as a class Map, that has properties filename, width and height. My general rule of thumb, is as soon as I have to start messing with my objects to get the xml, serialisation gets binned,and I add an interface that takes an XmlReader or Writer and implement it. Tryng to get serialisation to do what you want is usually way more code and far less comprehensible than doing that.
Upvotes: 0