locked
CDATA serialization with XMLSerializer RRS feed

  • Question

  • Hello,

    I have troubles serializing/desterilizing (with
    XmlSerializer) an XML node WITH attributes that contains CDATA. Sample:

    <root>

      <node attr1="value1" attr2="value2"><![CDATA[some text]]></node>

    </root>

    The following piece of code solves the problem when the <node> doesn't have any attribute:

     

    [XmlElement("node", typeof(XmlCDataSection))]

    public XmlCDataSection Node { get; set; }

     

    … but what about when <node> has attributes as in the sample above?

     


    Any help will be very appreciated,
    George

    Monday, July 13, 2009 3:48 PM

Answers

  • I've got it serializing correctly now. Try it out and see if it also deserializes:

        [XmlRoot("root")]
        public class Sample1Xml
        {
            [XmlElement("node")]
            public NodeType Node { get; set; }
    
            #region Nested type: NodeType
    
            public class NodeType
            {
                [XmlAttribute("attr1")]
                public string Attr1 { get; set; }
    
                [XmlAttribute("attr2")]
                public string Attr2 { get; set; }
    
                [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;
                    }
                }
            }
    
            #endregion
        }
    
    This produces:

    <?xml version="1.0" encoding="utf-8"?>
    <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <node attr1="attr1" attr2="attr2"><![CDATA[This is the <CData> content]]></node>
    </root>
    I got the answer from "Working with XSD.EXE generated classes and CDATA sections ".
    John Saunders
    WCF is Web Services. They are not two separate things.
    Use WCF for All New Web Service Development, instead of legacy ASMX or obsolete WSE
    Use File->New Project to create Web Service Projects
    Monday, July 13, 2009 6:37 PM
    Moderator

All replies

  • Obviously you can't represent three values in a type that only has one value. You'll need to create a class that has Attr1 and Attr2 properties as well as a Content property that will be XmlCDataSection.
    John Saunders
    WCF is Web Services. They are not two separate things.
    Use WCF for All New Web Service Development, instead of legacy ASMX or obsolete WSE
    Use File->New Project to create Web Service Projects
    Monday, July 13, 2009 4:11 PM
    Moderator
  • Thanks for the quick response!

     

    Can you please show me how the “Content property” would look like? I have already created such a class but I don’t know how to get to the CDATA:

     

    [XmlRoot("node")]

    public class NodeType

    {

        [XmlAttribute("attr1")]

        public string Attr1 { get; set; }

     

        [XmlAttribute("attr2")]

        public string Attr2 { get; set; }

     

        // how to represent the CDATA now?

    }

     

    And use it now:

     

    [XmlElement("node")]

    public NodeType Node { get; set; }

    Monday, July 13, 2009 4:24 PM
  • Just add:

    [XmlElement ("dontcare" , typeof (XmlCDataSection ))]

    public XmlCDataSection Content { get ; set ; }

    John Saunders
    WCF is Web Services. They are not two separate things.
    Use WCF for All New Web Service Development, instead of legacy ASMX or obsolete WSE
    Use File->New Project to create Web Service Projects
    Monday, July 13, 2009 4:33 PM
    Moderator
  • Unfortunately this doesn’t seem to work. The ‘Content’ is null:

     

        [XmlRoot("root")]

        [Serializable()]

        public class Sample1Xml

        {

            [XmlElement("node")]

            public NodeType Node { get; set; }

     

            [XmlRoot("node")]

            public class NodeType

            {

                [XmlAttribute("attr1")]

                public string Attr1 { get; set; }

     

                [XmlAttribute("attr2")]

                public string Attr2 { get; set; }

     

                [XmlElement("dontcare", typeof(XmlCDataSection))]

                public XmlCDataSection Content { get; set; }

            }

        }

     

     

        XmlSerializer xs1 = new XmlSerializer(typeof(Sample1Xml));

        Sample1Xml s1 = (Sample1Xml)xs1.Deserialize(stream);

     

     

    s1.Node.Content is null after this code runs.

    Monday, July 13, 2009 4:46 PM
  • I've got it serializing correctly now. Try it out and see if it also deserializes:

        [XmlRoot("root")]
        public class Sample1Xml
        {
            [XmlElement("node")]
            public NodeType Node { get; set; }
    
            #region Nested type: NodeType
    
            public class NodeType
            {
                [XmlAttribute("attr1")]
                public string Attr1 { get; set; }
    
                [XmlAttribute("attr2")]
                public string Attr2 { get; set; }
    
                [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;
                    }
                }
            }
    
            #endregion
        }
    
    This produces:

    <?xml version="1.0" encoding="utf-8"?>
    <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <node attr1="attr1" attr2="attr2"><![CDATA[This is the <CData> content]]></node>
    </root>
    I got the answer from "Working with XSD.EXE generated classes and CDATA sections ".
    John Saunders
    WCF is Web Services. They are not two separate things.
    Use WCF for All New Web Service Development, instead of legacy ASMX or obsolete WSE
    Use File->New Project to create Web Service Projects
    Monday, July 13, 2009 6:37 PM
    Moderator
  • This indeed solved the problem! Your code works perfectly with serialization but it has a small issue with deserialization because ‘node0’ it is not an ‘XmlCDataSection’ and the cast doesn’t succeed. The issue is easily solved with the code below:

     

    [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];

           

            if (node0 == null)

            {

                throw new InvalidOperationException(

                    String.Format(

                        "Invalid node type {0}", node0.NodeType));

            }

     

            Content = node0.Value;

        }

    }

     

    Thank you very much,

    George

    Tuesday, July 14, 2009 10:03 AM
  • Thanks for fixing it up. What type was node0?
    John Saunders
    WCF is Web Services. They are not two separate things.
    Use WCF for All New Web Service Development, instead of legacy ASMX or obsolete WSE
    Use File->New Project to create Web Service Projects
    Tuesday, July 14, 2009 11:42 AM
    Moderator
  • node0 is an XmlText.
    Thursday, July 16, 2009 10:21 AM