【问题标题】:.Net XmlSerializer: deserialize CDATA being inner text.Net XmlSerializer:将 CDATA 反序列化为内部文本
【发布时间】:2010-09-28 15:59:01
【问题描述】:

我在使用标准 .Net XmlSerializer 反序列化 CDATA 时遇到问题。

更新:我从外部系统获取 XML,我无法影响它的格式,因此我无法将 CData 包含在单独的属性元素中。

序列化给出了这个:

<?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"><![CDATA[Hello, world!]]></MyClass>

反序列化不会将对象恢复到其原始状态。

这是正在序列化的类:

public class MyClass
{
    string _data;

    [XmlIgnore]
    public string Data
    {
        get { return _data; }
        set { _data = value; }
    }

    [XmlAnyElement]
    public XmlCDataSection CData
    {
        get { return new XmlDataDocument().CreateCDataSection(Data); }
        set { Data = value.Value; }
    }
}

这是失败的测试:

[Test]
public void CData_as_inner_text_test()
{
    MyClass item = new MyClass();

    item.Data = "Hello, world!";

    XmlSerializer serializer = new XmlSerializer(item.GetType());
    string serialized;

    using (StringWriter sw = new StringWriter())
    {
        serializer.Serialize(sw, item);
        serialized = sw.GetStringBuilder().ToString();
    }

    MyClass deserialized;

    using (StringReader sr = new StringReader(serialized))
    {
        deserialized = (MyClass)serializer.Deserialize(sr);
    }

    Assert.AreEqual(item.Data, deserialized.Data); // For some reason, deserialized.Data == null
}

我在这里发现了同样的问题,但没有答案: XmlSerializer, XmlAnyElement and CDATA

【问题讨论】:

    标签: c# .net xml-serialization cdata


    【解决方案1】:

    CData 属性最终为 null,因为 CDATA 部分的内容最终在 Data 属性中,它被忽略...

    <MyClass><![CDATA[Hello, world!]]></MyClass>
    

    绝对等价于:

    <MyClass>Hello, world!</MyClass>
    

    您不应该关心外部应用程序是否将 MyClass 的内容写入 CData。同样,外部应用程序不应该关心你如何写出来。

    IOW,这应该就是你所需要的:

    public class MyClass
    {
        string _data;
    
        [XmlText]
        public string Data
        {
            get { return _data; }
            set { _data = value; }
        }
    }
    

    【讨论】:

    • 谢谢!看来我并没有真正意识到 CDATA 的作用。 Parser 只是忽略它并将其内容视为非格式化文本。您的答案中有一个小错误。我的 xml 绝对等同于 Hello, world! (“Hello, world!”周围没有'')
    • 你为什么假设内部文本是Hello, world!?如果它实际上需要是 CDATA 怎么办?
    • @Stijn:我不做任何这样的假设。至少从技术角度来看,它永远 不需要 是 CDATA 。 CDATA 只是为人类读者/作者提供便利。
    • @Stijn 如果它需要是 CDATA(如,数据包含 CDATA),您需要正确编码 CDATA(.NET 的序列化程序 将 做)。如果你需要它是 CDATA 因为你有一个愚蠢的解析器,你需要改变你的解析器:) CDATA 只是编码字符串的一种方式。 &lt;MyClass&gt;&lt;![CDATA[Hello, world!]]&gt;&lt;/MyClass&gt; 的数据与 &lt;MyClass&gt;Hello, world!&lt;/MyClass&gt; 的数据完全相同 - 如果您以任何方式依赖那里的 CDATA,那么您读取的 XML 都是错误的 :)
    【解决方案2】:

    首先声明一个属性为 XmlCDataSection

    public XmlCDataSection ProjectXml { get; set; }
    

    在这种情况下 projectXml 是一个字符串 xml

    ProjectXml = new XmlDocument().CreateCDataSection(projectXml);
    

    当您序列化您的消息时,您将拥有漂亮的格式(通知)

    <?xml version="1.0" encoding="utf-16"?>
    <MessageBase xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="Message_ProjectStatusChanged">
      <ID>131</ID>
      <HandlerName>Plugin</HandlerName>
      <NumRetries>0</NumRetries>
      <TriggerXml><![CDATA[<?xml version="1.0" encoding="utf-8"?><TmData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Version="9.0.0" Date="2012-01-31T15:46:02.6003105" Format="1" AppVersion="10.2.0" Culture="en-US" UserID="0" UserRole=""><PROJECT></PROJECT></TmData>]]></TriggerXml>
      <MessageCreatedDate>2012-01-31T20:28:52.4843092Z</MessageCreatedDate>
      <MessageStatus>0</MessageStatus>
      <ProjectId>0</ProjectId>
      <UserGUID>8CDF581E44F54E8BAD60A4FAA8418070</UserGUID>
      <ProjectGUID>5E82456F42DC46DEBA07F114F647E969</ProjectGUID>
      <PriorStatus>0</PriorStatus>
      <NewStatus>3</NewStatus>
      <ActionDate>0001-01-01T00:00:00</ActionDate>
    </MessageBase>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-03-13
      • 2021-07-16
      • 1970-01-01
      • 1970-01-01
      • 2021-11-06
      • 1970-01-01
      相关资源
      最近更新 更多