C
C#•2w ago
Billy

XML Deserialization

Hi, I want to deserialize an XML document and I'm using an XmlSerializer. That's all fine, but the order of the elements in the XML is important to me. For example, I might have some xml that looks like:
<books>
<book>
<header>header one</header>
<title>title one</title>
</book>
<book>
<title>title two</title>
<header>header two</header>
</book>
</books>
<books>
<book>
<header>header one</header>
<title>title one</title>
</book>
<book>
<title>title two</title>
<header>header two</header>
</book>
</books>
Where the title and header order is important to me. Is there any way to pull out the "index" of the xml tag when deserializing?
14 Replies
Angius
Angius•2w ago
The [XmlElement] attribute has an Order property, IIRC So
class Book
{
[XmlElement(Order=1)]
public required string Header { get; set; }
[XmlElement(Order=2)]
public required string Title { get; set; }
}
class Book
{
[XmlElement(Order=1)]
public required string Header { get; set; }
[XmlElement(Order=2)]
public required string Title { get; set; }
}
Billy
Billy•2w ago
But that would be for serializing it. I just want to deserialize it with the same order as the input xml. i.e. if I had something like:
class Book
{
[XmlElement]
public Header Header{ get; set; }
[XmlElement]
public Title Title { get; set; }
}

class Header : BaseElement
{
public string Text {get;set;}
}

class Title : BaseElement
{
public string Text {get;set;}
}

class BaseElement
{
public int Index {get;set;}
}
class Book
{
[XmlElement]
public Header Header{ get; set; }
[XmlElement]
public Title Title { get; set; }
}

class Header : BaseElement
{
public string Text {get;set;}
}

class Title : BaseElement
{
public string Text {get;set;}
}

class BaseElement
{
public int Index {get;set;}
}
Angius
Angius•2w ago
If you deserialize to a Book the order does not matter You never ever have to care about order of properties in a class
Billy
Billy•2w ago
This is a made up case. I'm actually deserializing the XML used to generate a PDF document, where the order does matter
Angius
Angius•2w ago
The order of properties is as it is declared in the class
Billy
Billy•2w ago
Sort of like as thought I was deserializing HTML I do in this case 🙂 not the order of the properties in the class, but the order that they were in the original XML
Angius
Angius•2w ago
So the order can vary?
Billy
Billy•2w ago
yeah and is important because the order is how is it displayed in a UI
Angius
Angius•2w ago
Aight, that changes things
Motley
Motley•2w ago
That is very not xml like I think you'd have to use a custom deserializer
Billy
Billy•2w ago
I know, but it is what I have to work with I was originally working with something like xElement.Elements().Select(o => { new { Node = o.Node, Index = o.Index }) etc but's getting complicated! (big "XML")
Motley
Motley•2w ago
Try something like this?
public class Book : IXmlSerializable
{
public Header Header { get; set; }
public Title Title { get; set; }

public XmlSchema GetSchema() => null;

public void ReadXml(XmlReader reader)
{
reader.MoveToContent();
int index = 1; // Start index counting

while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element && reader.Name == "Header")
{
Header = new Header { Index = index++ };
Header.ReadXml(reader);
}
else if (reader.NodeType == XmlNodeType.Element && reader.Name == "Title")
{
Title = new Title { Index = index++ };
Title.ReadXml(reader);
}
}
}

public void WriteXml(XmlWriter writer)
{
// Implement serialization logic if needed
}
}

public class Header : BaseElement, IXmlSerializable
{
public string Text { get; set; }

public void ReadXml(XmlReader reader)
{
reader.ReadStartElement("Header");
Text = reader.ReadElementContentAsString("Text", "");
reader.ReadEndElement();
}

public void WriteXml(XmlWriter writer)
{
// Implement serialization logic if needed
}
}
public class Book : IXmlSerializable
{
public Header Header { get; set; }
public Title Title { get; set; }

public XmlSchema GetSchema() => null;

public void ReadXml(XmlReader reader)
{
reader.MoveToContent();
int index = 1; // Start index counting

while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element && reader.Name == "Header")
{
Header = new Header { Index = index++ };
Header.ReadXml(reader);
}
else if (reader.NodeType == XmlNodeType.Element && reader.Name == "Title")
{
Title = new Title { Index = index++ };
Title.ReadXml(reader);
}
}
}

public void WriteXml(XmlWriter writer)
{
// Implement serialization logic if needed
}
}

public class Header : BaseElement, IXmlSerializable
{
public string Text { get; set; }

public void ReadXml(XmlReader reader)
{
reader.ReadStartElement("Header");
Text = reader.ReadElementContentAsString("Text", "");
reader.ReadEndElement();
}

public void WriteXml(XmlWriter writer)
{
// Implement serialization logic if needed
}
}
Can your book have multiple titles and headers or only one of each?
Billy
Billy•2w ago
Multiple Imagine something like
<node>
<p>Hi></p>
<p>Hello</p>
<p>Etc</p>
</node>
<node>
<p>Hi></p>
<p>Hello</p>
<p>Etc</p>
</node>
I actually want the index for all XmlElements, not just header and title, so not ideal above
Motley
Motley•2w ago
Can node just have a content property that is the of type List<BaseElement>? I'd start with a class model that you want to actually represent your structure and then ask for help on how to parse the Xml into that structure. You can fairly easily refactor the code I put above to handle most structures.