C# 如何使用XmlSerializer将字符串列表反序列化为CDATA

C# 如何使用XmlSerializer将字符串列表反序列化为CDATA,c#,serialization,xml-serialization,C#,Serialization,Xml Serialization,我需要将字符串列表序列化为CDATA,并认为我将遵循一个of 它就像连载的魅力。我的XML文件看起来符合要求: <?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"> <tlist> <item><![CD

我需要将字符串列表序列化为CDATA,并认为我将遵循一个of

它就像连载的魅力。我的XML文件看起来符合要求:

<?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">
 <tlist>
   <item><![CDATA[First string]]></item>
   <item><![CDATA[Second string]]></item>
 </tlist>
</root>

虽然简单代理使用单个值,但由于.NET XML序列化机制的工作方式,您必须对集合进行更深入的代理:

[XmlRootAttribute("root")]
public class TestConfig
{
    public TestConfig()
    {
        TestList = new List<string>();
    }

    private List<string> testList;

    [XmlIgnore]
    public List<string> TestList
    {
        get
        {
            if (this.testList == null)
            {
                var newCollection = new List<string>();

                if (this.cdataList != null)
                {
                    foreach (var x in this.cdataList)
                    {
                        newCollection.Add(x.Value);
                    }
                }

                this.testList = newCollection;
                this.cdataList = null;
            }

            return this.testList;
        }
        set
        {
            this.testList = value;
            this.cdataList = null;
        }
    }

    private List<XmlCDataSection> cdataList;

    [XmlArray("tlist")]
    [XmlArrayItem("item")]
    public List<XmlCDataSection> CdataList
    {
        get
        {
            if (this.cdataList == null)
            {
                var newCollection = new List<XmlCDataSection>();

                if (this.testList != null)
                {
                    foreach (var x in this.testList)
                    {
                        newCollection.Add(new XmlDocument().CreateCDataSection(x));
                    }
                }

                this.cdataList = newCollection;
                this.testList = null;
            }

            return this.cdataList;
        }
        set
        {
            this.cdataList = value;
            this.testList = null;
        }
    }

    public void Save(string path)
    {
        var serializer = new XmlSerializer(GetType());
        using (var stream = new StreamWriter(path))
        {
            serializer.Serialize(stream, this);
        }
    }

    public static TestConfig Load(string path)
    {
        var serializer = new XmlSerializer(typeof(TestConfig));
        using (var stream = new StreamReader(path))
        {
            return (TestConfig)serializer.Deserialize(stream);
        }
    }
}
然后按如下方式使用它:

var serializer = new XmlSerializer(...));
using (var cdataWriter = new XmlCDataWriter(XmlWriter.Create("somepath.xml")))
{
    serializer.Serialize(cdataWriter, myDocumentObject);
}
同样,只有当您想将所有内容都写为CDATA时,这个选项才有意义。

我想我应该通过减少XMLWriter子类的长度来“改进”答案

/// <summary>
/// Custom XmlWriter.
/// Wraps up another XmlWriter to intercept string writes within
/// elements and writes them as CDATA instead.
/// </summary>
public class XmlCDataWriter : XmlTextWriter
{

    public override void WriteString(string text)
    {
        if (WriteState == WriteState.Element)
        {
            WriteCData(text);
        }
        else
        {
            base.WriteString(text);
        }
    }

    /// <summary>
    /// Creates an instance of the XmlTextWriter class using the specified <see cref="T:System.IO.TextWriter"/>.
    /// </summary>
    /// <param name="w">The TextWriter to write to. It is assumed that the TextWriter is already set to the correct encoding. </param>
    public XmlCDataWriter( [NotNull] TextWriter w ) : base( w )
    {
    }
}

到目前为止似乎对我有效,它是一个小得多的子类:)

有没有一种紧凑的方法可以做到这一点,并且仍然允许使用XmlTextWriter XmlWriterSettings选项?XmlWriterSettings似乎只能通过XmlTextWriter.Create()静态方法使用。返回一个XmlWriter实例。无需。。。XmlWriter似乎已经包含了一个XmlWriterSettings成员变量,所以我刚刚添加了另一个构造函数,它接受XmlWriterSettings实例,并对我关心的所有内容进行深度复制。
/// <summary>
/// Custom XmlWriter.
/// Wraps up another XmlWriter to intercept string writes within
/// elements and writes them as CDATA instead.
/// </summary>
public class XmlCDataWriter : XmlWriter
{
    XmlWriter w;

    public XmlCDataWriter(XmlWriter baseWriter)
    {
        this.w = baseWriter;
    }

    public override void Close()
    {
        w.Close();
    }

    public override void Flush()
    {
        w.Flush();
    }

    public override string LookupPrefix(string ns)
    {
        return w.LookupPrefix(ns);
    }

    public override void WriteBase64(byte[] buffer, int index, int count)
    {
        w.WriteBase64(buffer, index, count);
    }

    public override void WriteCData(string text)
    {
        w.WriteCData(text);
    }

    public override void WriteCharEntity(char ch)
    {
        w.WriteCharEntity(ch);
    }

    public override void WriteChars(char[] buffer, int index, int count)
    {
        w.WriteChars(buffer, index, count);
    }

    public override void WriteComment(string text)
    {
        w.WriteComment(text);
    }

    public override void WriteDocType(string name, string pubid, string sysid, string subset)
    {
        w.WriteDocType(name, pubid, sysid, subset);
    }

    public override void WriteEndAttribute()
    {
        w.WriteEndAttribute();
    }

    public override void WriteEndDocument()
    {
        w.WriteEndDocument();
    }

    public override void WriteEndElement()
    {
        w.WriteEndElement();
    }

    public override void WriteEntityRef(string name)
    {
        w.WriteEntityRef(name);
    }

    public override void WriteFullEndElement()
    {
        w.WriteFullEndElement();
    }

    public override void WriteProcessingInstruction(string name, string text)
    {
        w.WriteProcessingInstruction(name, text);
    }

    public override void WriteRaw(string data)
    {
        w.WriteRaw(data);
    }

    public override void WriteRaw(char[] buffer, int index, int count)
    {
        w.WriteRaw(buffer, index, count);
    }

    public override void WriteStartAttribute(string prefix, string localName, string ns)
    {
        w.WriteStartAttribute(prefix, localName, ns);
    }

    public override void WriteStartDocument(bool standalone)
    {
        w.WriteStartDocument(standalone);
    }

    public override void WriteStartDocument()
    {
        w.WriteStartDocument();
    }

    public override void WriteStartElement(string prefix, string localName, string ns)
    {
        w.WriteStartElement(prefix, localName, ns);
    }

    public override WriteState WriteState
    {
        get { return w.WriteState; }
    }

    public override void WriteString(string text)
    {
        if (WriteState == WriteState.Element)
        {
            w.WriteCData(text);
        }
        else
        {
            w.WriteString(text);
        }
    }

    public override void WriteSurrogateCharEntity(char lowChar, char highChar)
    {
        w.WriteSurrogateCharEntity(lowChar, highChar);
    }

    public override void WriteWhitespace(string ws)
    {
        w.WriteWhitespace(ws);
    }
}
var serializer = new XmlSerializer(...));
using (var cdataWriter = new XmlCDataWriter(XmlWriter.Create("somepath.xml")))
{
    serializer.Serialize(cdataWriter, myDocumentObject);
}
/// <summary>
/// Custom XmlWriter.
/// Wraps up another XmlWriter to intercept string writes within
/// elements and writes them as CDATA instead.
/// </summary>
public class XmlCDataWriter : XmlTextWriter
{

    public override void WriteString(string text)
    {
        if (WriteState == WriteState.Element)
        {
            WriteCData(text);
        }
        else
        {
            base.WriteString(text);
        }
    }

    /// <summary>
    /// Creates an instance of the XmlTextWriter class using the specified <see cref="T:System.IO.TextWriter"/>.
    /// </summary>
    /// <param name="w">The TextWriter to write to. It is assumed that the TextWriter is already set to the correct encoding. </param>
    public XmlCDataWriter( [NotNull] TextWriter w ) : base( w )
    {
    }
}
using (StringWriter textWriter = new StringWriter())
{
    XmlSerializer serializer = new XmlSerializer( typeof( ... ) );
    serializer.Serialize(new XmlCDataWriter(textWriter), ... );
    return textWriter.ToString();
}