代码之家  ›  专栏  ›  技术社区  ›  jamesaharvey

如何使用XmlSerializer将字符串序列化为CDATA?

  •  75
  • jamesaharvey  · 技术社区  · 15 年前

    是否可以通过某种类型的属性使用.NET XmlSerializer将字符串序列化为CDATA?

    7 回复  |  直到 5 年前
        1
  •  59
  •   John Saunders KB22    15 年前
    [XmlRoot("root")]
    public class Sample1Xml
    {
        internal 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));
                    }
    
                    Content = value[0].Value;
                }
            }
        }
    
        #endregion
    }
    
        2
  •  88
  •   pr0gg3r    9 年前
    [Serializable]
    public class MyClass
    {
        public MyClass() { }
    
        [XmlIgnore]
        public string MyString { get; set; }
        [XmlElement("MyString")]
        public System.Xml.XmlCDataSection MyStringCDATA
        {
            get
            {
                return new System.Xml.XmlDocument().CreateCDataSection(MyString);
            }
            set
            {
                MyString = value.Value;
            }
        }
    }
    

    用途:

    MyClass mc = new MyClass();
    mc.MyString = "<test>Hello World</test>";
    XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
    StringWriter writer = new StringWriter();
    serializer.Serialize(writer, mc);
    Console.WriteLine(writer.ToString());
    

    输出:

    <?xml version="1.0" encoding="utf-16"?>
    <MyClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <MyString><![CDATA[<test>Hello World</test>]]></MyString>
    </MyClass>
    
        3
  •  86
  •   Dan Atkinson    6 年前

    除了约翰·桑德斯发布的方式外,您还可以使用 XmlCDataSection 直接作为类型,尽管归根结底几乎是相同的事情:

    private string _message;
    [XmlElement("CDataElement")]
    public XmlCDataSection Message
    {  
        get 
        { 
            XmlDocument doc = new XmlDocument();
            return doc.CreateCDataSection( _message);
        }
        set
        {
            _message = value.Value;
        }
    }
    
        4
  •  33
  •   sagis    10 年前

    在要序列化的类中:

    public CData Content { get; set; }
    

    和CDATA类:

    public class CData : IXmlSerializable
    {
        private string _value;
    
        /// <summary>
        /// Allow direct assignment from string:
        /// CData cdata = "abc";
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static implicit operator CData(string value)
        {
            return new CData(value);
        }
    
        /// <summary>
        /// Allow direct assigment to string
        /// string str = cdata;
        /// </summary>
        /// <param name="cdata"></param>
        /// <returns></returns>
        public static implicit operator string(CData cdata)
        {
            return cdata._value;
        }
    
        public CData() : this(string.Empty)
        {
        }
    
        public CData(string value)
        {
            _value = value;
        }
    
        public override string ToString()
        {
            return _value;
        }
    
        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }
    
        public void ReadXml(System.Xml.XmlReader reader)
        {
            _value = reader.ReadElementString();
        }
    
        public void WriteXml(System.Xml.XmlWriter writer)
        {
            writer.WriteCData(_value);
        }
    }
    
        5
  •  3
  •   Coderookie    8 年前

    在我的例子中,我使用的是混合字段,一些是CDATA,一些不是, 至少对我来说,下面的解决方案是有效的……

    通过总是阅读值字段,我得到了内容,不管是CDATA还是纯文本。

        [XmlElement("")]
        public XmlCDataSection CDataValue {
            get {
                return new XmlDocument().CreateCDataSection(this.Value);
            }
            set {
                this.Value = value.Value;
            }
        }
    
        [XmlText]
        public string Value;
    

    迟到总比不迟到好。

    干杯

        6
  •  2
  •   Iain Fraser    8 年前

    此实现能够处理您正在编码的字符串中的嵌套CDATA(基于JohnSaunders的原始答案)。

    例如,假设您希望将以下文本字符串编码为CDATA:

    I am purposefully putting some <![CDATA[ cdata markers right ]]> in here!!
    

    您希望结果输出如下所示:

    <![CDATA[I am purposefully putting some <![CDATA[ cdata markers right ]]]]><![CDATA[> in here!!]]>
    

    以下实现将循环字符串,拆分 ...]]>... 进入之内 ...]] >... 并为每个部分创建单独的CDATA部分。

    [XmlRoot("root")]
    public class Sample1Xml
    {
        internal 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
                {
                    XmlDocument dummy = new XmlDocument();
                    List<XmlNode> xmlNodes = new List<XmlNode>();
                    int tokenCount = 0;
                    int prevSplit = 0;
                    for (int i = 0; i < Content.Length; i++)
                    {
                        char c = Content[i];
                        //If the current character is > and it was preceded by ]] (i.e. the last 3 characters were ]]>)
                        if (c == '>' && tokenCount >= 2)
                        {
                            //Put everything up to this point in a new CData Section
                            string thisSection = Content.Substring(prevSplit, i - prevSplit);
                            xmlNodes.Add(dummy.CreateCDataSection(thisSection));
                            prevSplit = i;
                        }
                        if (c == ']')
                        {
                            tokenCount++;
                        }
                        else
                        {
                            tokenCount = 0;
                        }
                    }
                    //Put the final part of the string into a CData section
                    string finalSection = Content.Substring(prevSplit, Content.Length - prevSplit);
                    xmlNodes.Add(dummy.CreateCDataSection(finalSection));
    
                    return xmlNodes.ToArray();
                }
                set
                {
                    if (value == null)
                    {
                        Content = null;
                        return;
                    }
    
                    if (value.Length != 1)
                    {
                        throw new InvalidOperationException(
                            String.Format(
                                "Invalid array length {0}", value.Length));
                    }
    
                    Content = value[0].Value;
                }
            }
        }
    
        7
  •  2
  •   Adam Hey    7 年前

    我有类似的需求,但需要不同的输出格式——我需要在包含CDATA的节点上有一个属性。我从上面的解决方案中获得了一些灵感,创建了自己的解决方案。也许它将来会帮助别人…

    public class EmbedScript
    {
        [XmlAttribute("type")]
        public string Type { get; set; }
    
        [XmlText]
        public XmlNode[] Script { get; set; }
    
        public EmbedScript(string type, string script)
        {
            Type = type;
            Script = new XmlNode[] { new XmlDocument().CreateCDataSection(script) };
        }
    
        public EmbedScript()
        {
    
        }
    }
    

    在要序列化的父对象中,我具有以下属性:

        [XmlArray("embedScripts")]
        [XmlArrayItem("embedScript")]
        public List<EmbedScript> EmbedScripts { get; set; }
    

    我得到以下输出:

    <embedScripts>
        <embedScript type="Desktop Iframe">
            <![CDATA[<div id="play_game"><iframe height="100%" src="http://www.myurl.com" width="100%"></iframe></div>]]>
        </embedScript>
        <embedScript type="JavaScript">
            <![CDATA[]]>
        </embedScript>
    </embedScripts>