How to serialize / deserialize a node of type CDATA

3

The next class (of an xml) has several attributes and contains text.

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.6.1055.0")]
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "xxx")]
public partial class consultaSelect : EntityBase<consultaSelect>
{
   private string scriptField;

    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string script
    {
        get
        {
            return this.scriptField;
        }
        set
        {
            if ((this.scriptField != null))
            {
                if ((scriptField.Equals(value) != true))
                {
                    this.scriptField = value;
                    this.OnPropertyChanged("script");
                }
            }
            else
            {
                this.scriptField = value;
                this.OnPropertyChanged("script");
            }
        }
    }
    private string valueField;
    [System.Xml.Serialization.XmlTextAttribute()]
    public string Value
    {
        get
        {
            return this.valueField;
        }
        set
        {
            if ((this.valueField != null))
            {
                if ((valueField.Equals(value) != true))
                {
                    this.valueField = value;
                    this.OnPropertyChanged("Value");
                }
            }
            else
            {
                this.valueField = value;
                this.OnPropertyChanged("Value");
            }
        }
    }
}

The problem is with value. I want it to be a CDATA. However, when writing the get as follows:

get
{
    XmlDocument doc = new XmlDocument();
    return doc.CreateCDataSection(valueField);
}

this in theory returns the value as CDATA, but forces me to decorate it with a [XmlElement("CDataElement")] tag that is not what I want, since I want it to be part of the original. When I decorate it in that way, it generates one more element in the final XML:

<select script="pepe">
    <CDataElement><![CDATA[SELECT * FROM Users WHERE UserId > 10]]></CDataElement>
</select>

and what I want is:

<select script="pepe">
    <![CDATA[SELECT * FROM Users WHERE UserId > 10]]>
</select>

So the problem is, should I decorate it in another way, or am I totally wrong and I have to do it in a different way?

    
asked by gbianchi 07.09.2017 в 17:20
source

2 answers

1

I hope these modifications will serve you. Add the following in your class

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace ConsoleApp1
{
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.6.1055.0")]
    [System.SerializableAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    //[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "xxx")]
    public partial class select : IXmlSerializable//: EntityBase<consultaSelect>
    {
        public select()
        {

        }

        public select(string script, string value)
        {
            Script = script;
            Value = value;
        }


        private string scriptField;

        [System.Xml.Serialization.XmlAttributeAttribute()]
        public string Script
        {
            get
            {
                return this.scriptField;
            }
            set
            {
                if ((this.scriptField != null))
                {
                    if ((scriptField.Equals(value) != true))
                    {
                        this.scriptField = value;
                        //this.OnPropertyChanged("script");
                    }
                }
                else
                {
                    this.scriptField = value;
                    //this.OnPropertyChanged("script");
                }
            }
        }
        private string valueField;
        [System.Xml.Serialization.XmlTextAttribute()]
        public string Value
        {
            get
            {
                return this.valueField;
            }
            set
            {
                if ((this.valueField != null))
                {
                    if ((valueField.Equals(value) != true))
                    {
                        this.valueField = value;
                        //this.OnPropertyChanged("Value");
                    }
                }
                else
                {
                    this.valueField = value;
                    //this.OnPropertyChanged("Value");
                }
            }
        }

        XmlSchema IXmlSerializable.GetSchema()
        {
            return null;
        }

        void IXmlSerializable.ReadXml(XmlReader reader)
        {
            if (reader.MoveToContent() == XmlNodeType.Element)
            {
                Script = reader.GetAttribute("script");
                reader.Read();
                Value = reader.Value.ToString(); ;
            }
        }

        void IXmlSerializable.WriteXml(XmlWriter writer)
        {
            writer.WriteAttributeString("script", Script);
            writer.WriteCData(Value);
        }

    }

    class Program
    {
        static void Main(string[] args)
        {
            var toSerialize = new select() { Script = "pepe", Value = "SELECT * FROM Users WHERE UserId > 10" };
            var xmlToDeserialize = "<select script=\"pepe\"><![CDATA[SELECT * FROM Users WHERE UserId > 10]]></select>";

            var result = Serialize<select>(toSerialize);

            var objetDeserialized  = Deserialize<select>(xmlToDeserialize);
            Console.WriteLine(result);

            Console.ReadKey();

        }

        private static string Serialize<T>(T toSerialize)
        {  
            var serializer = new XmlSerializer(typeof(T));

            using (StringWriter textWriter = new StringWriter())
            {
                serializer.Serialize(textWriter, toSerialize);
                return textWriter.ToString();
            }
        }

        private static T Deserialize<T>(string toSerialize)
        {
            var serializer = new XmlSerializer(typeof(T));

            using (StringReader textReader = new StringReader(toSerialize))
            {
                return (T)serializer.Deserialize(textReader);
            }
        }
    }
}
    
answered by 08.09.2017 / 17:09
source
1

As a reference, the solution proposed by Sergio is totally correct. However in my case the XML is much more complex and that's why I needed to do it with automatic decorators. To avoid that, I did the following (although it is not recommended):

Add the following in the class:

/// <summary>
/// Serializa, pero no deserializa
/// </summary>
[XmlAnyElement]
public XmlCDataSection CData
{
    get { return new XmlDocument().CreateCDataSection(Value); }
    set { Value = value.Value; }
}

and also decorate the Value element as

[XmlIgnore]
public string Value

After this, the only thing I did was add a procedure, after deserializing the XML, that I read by hand the CDATA elements that I wanted and I saved them in the class:

public static void ObtenerSelectCdata(consulta cons, string rutaarchivo)
{
   XNamespace aw = "xxx";
   XElement NodoConsulta;
   //Abro el archivo
   XDocument documento = new XDocument();
   documento = XDocument.Load(rutaarchivo);
   NodoConsulta = documento.Element(aw + "consulta");
   //Obtengo los nodos Select
   var elementos = NodoConsulta.Elements(aw + "select");
   if (elementos== null)
   {
     //No hay nodos select
     return;
   }
   //Ahora por cada Select que haya en consulta, busco su contenido
   foreach (consultaSelect s in cons.select)
   {
      foreach (XElement xe in elementos)
      {
         if (s.nombreAccion== xe.Attribute("nombreAccion").Value)
         {
             s.Value = xe.Value;
             break;
         }
      }

   }
}
    
answered by 11.09.2017 в 16:51