2

I have the following XML:

<MyType>
  <MyProperty1>Value 1</MyProperty1>
  <MyProperty2>Value 2</MyProperty2>
  <MyNestedXml>
    <h1>Heading</h1>
    <p>Lorum</p>
    <p>Ipsum</p>
  </MyNestedXml>
</MyType>

This can be deserialized to XML in C# by creating classes and adding attributes as below:

[Serializable]
public class MyType
{
    [XmlElement("MyProperty1")
    public string MyProperty1 { get; set; }

    [XmlElement("MyProperty2")
    public string MyProperty2 { get; set; }

    [XmlIgnore]
    public string MyNestedXml { get; set; }
}

However, the inner XML within the <MyNestedXml> element varies and doesn't follow a consistent structure which I can effectively map using attributes.

I don't have control over the XML structure unfortunately.

I have tried using an [XmlElement("MyNestedXml") with an XmlNode type but this results in the first child node being deserialized instead of the entire inner XML.

I have also tried deserializing to a type of string but that throws an InvalidOperationException:

"Unexpected node type Element. ReadElementString method can only be called on elements with simple or empty content."

The problem is that the content of the MyNestedXml element could be an array of Elements sometimes but could be simple or empty content at other times.

Ideally I could use a different serialization attribute such as [XmlAsString] to skip serialization altogether and just assign the inner XML as is.

The intended result would be a class of type MyType having a property MyProperty1 = "Value 1", a property MyProperty2 = "Value 2", and a property MyNestedXml = "<h1>Heading</h1><p>Lorum</p><p>Ipsum</p>".

Mr Lister
  • 45,515
  • 15
  • 108
  • 150
John Askew
  • 233
  • 1
  • 12

3 Answers3

4

Make it an XmlElement property with the XmlAnyElement attribute and the serializer will deserialize an arbitrary XML structure.

[XmlRoot("MyType")]
public class MyType
{
    [XmlElement("MyProperty1")]
    public string MyProperty1 { get; set; }

    [XmlElement("MyProperty2")]
    public string MyProperty2 { get; set; }

    [XmlAnyElement("MyNestedXml")]
    public XmlElement MyNestedXml { get; set; }
}
madreflection
  • 4,744
  • 3
  • 19
  • 29
  • Just tried this out and it works to expose an XmlElement which I can subsequently call .InnerXml on for my desired string value. – John Askew Nov 16 '16 at 00:17
3

I have managed to solve this...

I created a class to deserialize to:

public class RichText : IXmlSerializable
{
    public string Raw { get; set; }

    public XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
        Raw = reader.ReadInnerXml();
    }

    public void WriteXml(XmlWriter writer)
    {
        writer.WriteString(Raw);
    }
}

This allows me to have the following class definition:

[Serializable]
public class MyType
{
    [XmlElement("MyProperty1")
    public string MyProperty1 { get; set; }

    [XmlElement("MyProperty2")
    public string MyProperty2 { get; set; }

    [XmlElement("MyNestedXml")]
    public RichText MyNestedXml { get; set; }
}

I can now use InstanceOfMyType.MyNestedXml.Raw to get the inner XML as string. If I so choose I can override the .ToString() method of RichText to return the Raw property also.

Hope this helps others out in the future.

John Askew
  • 233
  • 1
  • 12
0

You're going to have to use an XMLReader if the structure of the XML isn't consistent.

I'd suggest you look at this link for a recursion pattern on how to use an XMLReader. It is probably also going to be the fastest way to parse the XML as well.

Traverse a XML using Recursive function

Community
  • 1
  • 1
Paul Mendoza
  • 5,709
  • 12
  • 53
  • 82