3

Can you deserilize XML ('items') inside another tag ('data') more simple without using another deserilization inside 'Items' get property. Maybe some kind of a attribute on "public Item[] Items".

XML:

<body>
  <request></request>
  <data><![CDATA[
    <items>
      <item>
        <property1>Name1</property1>
        <property2>111</property2>
      </item>
      <item>
        <property1>Name2</property1>
        <property2>222</property2>
      </item>
      <item>
        <property1>Name3</property1>
        <property2>333</property2>
      </item>
    </items>]]>
  </data>
</body>

TestClass:

    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            const string xml = "<body>" +
                                    "<request></request>" +
                                    "<data><![CDATA[" +
                                        "<items>" +
                                            "<item>" +
                                                "<property1>Name1</property1>" +
                                                "<property2>111</property2>" +
                                            "</item>" +
                                            "<item>" +
                                                "<property1>Name2</property1>" +
                                                "<property2>222</property2>" +
                                            "</item>" +
                                            "<item>" +
                                                "<property1>Name3</property1>" +
                                                "<property2>333</property2>" +
                                            "</item>" +
                                        "</items>" +
                                    "]]></data>" +
                               "</body>";

            var xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(xml);

            var serializer = new XmlSerializer(typeof (Body));
            var response = serializer.Deserialize(new XmlNodeReader(xmlDoc)) as Body;

            Assert.IsNotNull(response);
            Assert.AreEqual(3, response.Items.Length);
        }
    }

    [Serializable, XmlRoot("body")]
    public class Body
    {
        [XmlElement("request")] 
        public string Request;

        [XmlElement("data")] 
        public string Data;

        public Item[] Items
        {
            get
            {
                var document = new XmlDocument();
                document.LoadXml(Data);

                var serializer = new XmlSerializer(typeof(ItemList));
                var response = serializer.Deserialize(new XmlNodeReader(document)) as ItemList;

                return response.Items;
            }
        }
    }

    [Serializable, XmlRoot("items")]
    public class ItemList
    {
        [XmlElement("item")]
        public Item[] Items;
    }

    [Serializable]
    public class Item
    {
        [XmlElement("property1")]
        public string Property1;

        [XmlElement("property2")]
        public string Property2;
    }
Dariusz Woźniak
  • 9,640
  • 6
  • 60
  • 73
sulgpallur
  • 63
  • 5
  • 1
    Any reason you're using `CData` in this instance? Why not let `Items` serialize/deserialize themselves normally without the `Data` property? – Chris Sinclair Aug 01 '13 at 12:52
  • i get this xml with CData from another system – sulgpallur Aug 01 '13 at 12:54
  • 3
    The trouble is that the CData and the fact that Data is a string means that technically what is inside Data is a single string, not XML so you are not going to be able to deserialise it without two steps. – Chris Aug 01 '13 at 12:56
  • Ok, thanks for explaining, i will work around it – sulgpallur Aug 01 '13 at 12:57
  • 1
    Hrrm, well, I'm not aware of an XmlAttribute that could be applied (I've been wrong about that before though). If I had the same requirement, I'd do it pretty much the same way. Although I'd consider a bit of caching or writing the `Items` array once in the `Data` setter to avoid deserializing every time the `Items` property is accessed. – Chris Sinclair Aug 01 '13 at 12:58
  • @Chris: [this question ain't big enough for the two of us...](https://www.youtube.com/watch?v=vHcH7mDMlmM) – Chris Sinclair Aug 01 '13 at 12:59
  • @user1525437: @Chris is right. That `CDATA` node is going to prevent you from deserializing the contents as XML. You'll have to get the text of the `CDATA` node and instantiate another `XmlDocument` and call the `LoadXml` method with the string data from the `CDATA` section. – fourpastmidnight Aug 01 '13 at 13:24
  • Is it possible to replace the string to get a cleaner XML, like xml = xml.Replace("<![CDATA[", "" ).Replace( "]]>", "" ); – ibram Aug 01 '13 at 14:19
  • @ibram, Yes replacing part of the XML is possible, because I just need to get items from the list and not XML itself which comes as a part of SOAP response – sulgpallur Aug 01 '13 at 15:06

1 Answers1

0

Before deserializing XML, load XML into XmlDocument and change "data" XmlNode InnerXml as below:

if (xmlNode.Contains("<![CDATA[") || xmlNode.InnerXml.Contains("&lt;"))
{
     xmlNode.InnerXml = xmlNode.Value;
}

This will work if you know what you will be receiving inside CDATA.

Morbia
  • 4,144
  • 3
  • 21
  • 13