JanDotNet
JanDotNet

Reputation: 4016

How to prevent XmlSerialzer from escaping "nested XML"?

I am using an XmlSerializer to serialize / deserialize complex objects. One property contains an XML string that should be written into a string property without deserialization.

Example (executable in LinqPad):

[XmlRoot("RootObject")]
[Serializable]
public class RootClass
{
    [XmlArray("SubObjects")]
    [XmlArrayItem("SubObject")]
    public SubClass[] SubObjecs { get; set;} 
}

[Serializable]
public class SubClass
{
    [XmlElement("XmlConfiguration")]
    public string XmlConfiguration { get; set;}
}

void Main()
{
    var obj = new RootClass()
    {
        SubObjecs = new[]
        {
            new SubClass { XmlConfiguration = "<ConfigurationX>SomeConfiguration1</ConfigurationX>" },
            new SubClass { XmlConfiguration = "<ConfigurationY>SomeConfiguration2</ConfigurationY>" }
        }
    };

    var serializer = new XmlSerializer(typeof(RootClass));
    using (var stream = new MemoryStream())
    {
        serializer.Serialize(stream, obj);
        stream.Position = 0;
        Console.WriteLine(Encoding.UTF8.GetString(stream.GetBuffer()));
    }
}

The output of the example is:

<?xml version="1.0"?>
<RootObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <SubObjects>
        <SubObject>
            <XmlConfiguration>&lt;ConfigurationX&gt;SomeConfiguration1&lt;/ConfigurationX&gt;</XmlConfiguration>
        </SubObject>
        <SubObject>
            <XmlConfiguration>&lt;ConfigurationY&gt;SomeConfiguration2&lt;/ConfigurationY&gt;</XmlConfiguration>
        </SubObject>
    </SubObjects>
</RootObject>

The XML is a configuration file that is sometimes written programmatically, but mainly written / modified by humans. Therefore the XML within XmlConfiguration should not contain escaped characters.

Question: Is it possible to prevent the XmlSerializer from escaping the '<' and '>' characters? If not, Is there another serializer that can be used?

One option that works is XmlWriter.WriteRaw. However, if somehow possible I would avoid that unreliable and less maintainable solution.


I found a similar question here: How to prevent XmlSerializer from escaping < and > characters. But that question is related to !CDATA[[Content]] and has no answer for my problem.

Upvotes: 3

Views: 3520

Answers (2)

Iren Saltalı
Iren Saltalı

Reputation: 536

If you need CDATA encapsulation you can use XmlCDataSection Class for this. You following class as type of your xml element. You can change names or attributes as you need it for every different type of element.

public class XmlConfiguration //Or any other class name.
    {
        [XmlAttribute("attr1")]
        public string Attr1 { get; set; } //You don't need this but use if you need attribute.

        [XmlAttribute("attr2")]
        public string Attr2 { get; set; } //Or second one.

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

        [XmlText]
        public XmlNode[] CDataContent
        {
            get
            {
                var dummy = new XmlDocument();
                return new XmlNode[] {dummy.CreateCDataSection(Content)};
            }
            set
            {
                if (value == null)
                {
                    Content = null;
                    return;
                }

                if (value.Length != 1)
                {
                    throw new InvalidOperationException(
                        String.Format(
                            "Invalid array length {0}", value.Length));
                }

                var node0 = value[0];
                var cdata = node0 as XmlCDataSection;
                if (cdata == null)
                {
                    throw new InvalidOperationException(
                        String.Format(
                            "Invalid node type {0}", node0.NodeType));
                }

                Content = cdata.Data;
            }
        }
    }

I found this answer here. Check the link for complete discussion.

Upvotes: 0

JanDotNet
JanDotNet

Reputation: 4016

As mentioned above in comment by dbc, there is a solution that uses the XmlAnyElement attribute as described here: Deserialize dynamic XML


I found a solution that is a mixture of XmlSerializer and XmlWriter.WriteRaw. When implementing IXmlSerializable, it is possible to control the serialization process of the XmlSerializer. Therfore IXmlSerializable has to be implemented just for the class that needs special handling (which is OK for me):

[Serializable]
public class SubClass : IXmlSerializable
{
    [XmlElement("XmlConfiguration")]
    public string XmlConfiguration { get; set; }

    public void WriteXml(XmlWriter writer)
    {
        writer.WriteStartElement("XmlConfiguration");
        writer.WriteRaw(XmlConfiguration);
        writer.WriteEndElement();
    }

    public void ReadXml(XmlReader reader)
    {
        reader.ReadToDescendant("XmlConfiguration");
        XmlConfiguration = reader.ReadInnerXml();
        reader.ReadEndElement();
    }

    public XmlSchema GetSchema()
    {
        return (null);
    }
}

Upvotes: 4

Related Questions