XML 序列化 - XmlCDataSection 作为 Serialization.XmlText

发布于 2024-08-04 10:18:29 字数 995 浏览 10 评论 0原文

我在使用 c# 序列化 cdata 部分时遇到问题,

我需要将 XmlCDataSection 对象属性序列化为元素的内部文本。

我正在寻找的结果是这样的:

<Test value2="Another Test">
  <![CDATA[<p>hello world</p>]]>
</Test>

为了生成这个,我正在使用这个对象:

public class Test
{
    [System.Xml.Serialization.XmlText()]
    public XmlCDataSection value { get; set; }

    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string value2 { get; set; }
}

在 value 属性上使用 xmltext 注释时,会引发以下错误。

系统.InvalidOperationException: 反映属性时出现错误 '价值'。 ---> 系统.InvalidOperationException: 无法序列化成员“值” 类型 System.Xml.XmlCDataSection。 XmlAttribute/XmlText 不能用于 编码复杂类型

如果我注释掉注释,序列化将起作用,但 cdata 部分被放置到一个值元素中,这对我想做的事情没有好处:

<Test value2="Another Test">
  <value><![CDATA[<p>hello world</p>]]></value>
</Test>

任何人都可以为我指出正确的方向以使其工作。

谢谢,亚当

I am having problems serializing a cdata section using c#

I need to serialize XmlCDataSection object property as the innertext of the element.

The result I am looking for is this:

<Test value2="Another Test">
  <![CDATA[<p>hello world</p>]]>
</Test>

To produce this, I am using this object:

public class Test
{
    [System.Xml.Serialization.XmlText()]
    public XmlCDataSection value { get; set; }

    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string value2 { get; set; }
}

When using the xmltext annotation on the value property the following error is thrown.

System.InvalidOperationException:
There was an error reflecting property
'value'. --->
System.InvalidOperationException:
Cannot serialize member 'value' of
type System.Xml.XmlCDataSection.
XmlAttribute/XmlText cannot be used to
encode complex types

If I comment out the annotation, the serialization will work but the cdata section is placed into a value element which is no good for what I am trying to do:

<Test value2="Another Test">
  <value><![CDATA[<p>hello world</p>]]></value>
</Test>

Can anybody point me in the right direction to getting this to work.

Thanks, Adam

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

晚风撩人 2024-08-11 10:18:29

谢谢理查德,现在才有机会回到这个话题。我想我已经按照你的建议解决了这个问题。我使用以下命令创建了一个 CDataField 对象:

public class CDataField : IXmlSerializable
    {
        private string elementName;
        private string elementValue;

        public CDataField(string elementName, string elementValue)
        {
            this.elementName = elementName;
            this.elementValue = elementValue;
        }

        public XmlSchema GetSchema()
        {
            return null;
        }

        public void WriteXml(XmlWriter w)
        {
            w.WriteStartElement(this.elementName);
            w.WriteCData(this.elementValue);
            w.WriteEndElement();
        }

        public void ReadXml(XmlReader r)
        {                      
            throw new NotImplementedException("This method has not been implemented");
        }
    }

Thanks Richard, only now had chance to get back to this. I think I have resolved the problem by using your suggestion. I have created a CDataField object using the following:

public class CDataField : IXmlSerializable
    {
        private string elementName;
        private string elementValue;

        public CDataField(string elementName, string elementValue)
        {
            this.elementName = elementName;
            this.elementValue = elementValue;
        }

        public XmlSchema GetSchema()
        {
            return null;
        }

        public void WriteXml(XmlWriter w)
        {
            w.WriteStartElement(this.elementName);
            w.WriteCData(this.elementValue);
            w.WriteEndElement();
        }

        public void ReadXml(XmlReader r)
        {                      
            throw new NotImplementedException("This method has not been implemented");
        }
    }
驱逐舰岛风号 2024-08-11 10:18:29

按照 Test 的定义方式,您的数据是一个 CData 对象。因此序列化系统正在尝试保留 CData 对象。

但您想要将一些文本数据序列化为 CData 部分。

所以首先,Test.value 的类型应该是 String。

然后,您需要控制该字段的序列化方式,但似乎没有任何内置方法或属性来控制字符串的序列化方式(作为字符串,可能带有保留字符的实体,或作为 CDATA)。 (因为,从 XML 信息集的角度来看,所有这些都是相同的,这并不奇怪。)

您当然可以实现 IXmlSerialized,并且只需自己编写 Test 类型的序列化代码,这样您就可以完全控制。

The way Test is defined, your data is a CData object. So the serialisation system is trying to preserve the CData object.

But you want to serialise some text data as a CData section.

So first, the type of Test.value should be String.

You then need to control how that field is serialised, but there does not appear to be any inbuilt method or attribute to control how strings are serialised (as string, maybe with entities for reserved characters, or as CDATA). (Since, from an XML infoset perspective all of these are the same, this is not surprising.)

You can of course implemented IXmlSerializable and just code the serialisation of the Test type yourself which gives you complete control.

翻了热茶 2024-08-11 10:18:29

这基本上是杰克答案的较短版本,具有更好的错误消息:

[XmlIgnore]
public string Content { get; set; }

[XmlText]
public XmlNode[] ContentAsCData
{
    get => new[] { new XmlDocument().CreateCDataSection(Content) };
    set => Content = value?.Cast<XmlCDataSection>()?.Single()?.Data;
}

This basically shorter version of Jack answer with better error messages:

[XmlIgnore]
public string Content { get; set; }

[XmlText]
public XmlNode[] ContentAsCData
{
    get => new[] { new XmlDocument().CreateCDataSection(Content) };
    set => Content = value?.Cast<XmlCDataSection>()?.Single()?.Data;
}
稀香 2024-08-11 10:18:29

刚刚从 此处

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

Just found an alternative from here:

     [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;
                }
            }
        }
妖妓 2024-08-11 10:18:29

我和亚当有同样的问题。然而这个答案并没有100%帮助我:)但给了我一个线索。所以我创建了如下代码。它生成这样的 XML:

<Actions>
    <Action Type="reset">
      <![CDATA[
      <dbname>longcall</dbname>
      <ontimeout>
       <url>http://[IPPS_ADDRESS]/</url>
       <timeout>10</timeout>
      </ontimeout>
      ]]>
    </Action>
    <Action Type="load">
      <![CDATA[
      <dbname>longcall</dbname>
      ]]>
    </Action>
</Actions>

代码:

public class ActionsCDataField : IXmlSerializable
{
    public List<Action> Actions { get; set; }

    public ActionsCDataField()
    {
        Actions = new List<Action>();
    }

    public XmlSchema GetSchema()
    {
        return null;
    }

    public void WriteXml(XmlWriter w)
    {
        foreach (var item in Actions)
        {
            w.WriteStartElement("Action");
            w.WriteAttributeString("Type", item.Type);
            w.WriteCData(item.InnerText);                
            w.WriteEndElement();
            w.WriteString("\r\n");
        }
    }

    public void ReadXml(XmlReader r)
    {
        XmlDocument xDoc = new XmlDocument();
        xDoc.Load(r);

        XmlNodeList nodes = xDoc.GetElementsByTagName("Action");
        if (nodes != null && nodes.Count > 0)
        {
            foreach (XmlElement node in nodes)
            {
                Action a = new Action();
                a.Type = node.GetAttribute("Type");
                a.InnerText = node.InnerXml;
                if (a.InnerText != null && a.InnerText.StartsWith("<![CDATA[") && a.InnerText.EndsWith("]]>"))
                    a.InnerText = a.InnerText.Substring("<![CDATA[".Length, a.InnerText.Length - "<![CDATA[]]>".Length);

                Actions.Add(a);
            }
        }
    }
}

public class Action
{
    public String Type { get; set; }
    public String InnerText { get; set; }
}

I had very same problem as Adam. However this Answer does not helped me at 100% :) but gives me a clue. So I'va created a code like below. It generates XML like this:

<Actions>
    <Action Type="reset">
      <![CDATA[
      <dbname>longcall</dbname>
      <ontimeout>
       <url>http://[IPPS_ADDRESS]/</url>
       <timeout>10</timeout>
      </ontimeout>
      ]]>
    </Action>
    <Action Type="load">
      <![CDATA[
      <dbname>longcall</dbname>
      ]]>
    </Action>
</Actions>

Code:

public class ActionsCDataField : IXmlSerializable
{
    public List<Action> Actions { get; set; }

    public ActionsCDataField()
    {
        Actions = new List<Action>();
    }

    public XmlSchema GetSchema()
    {
        return null;
    }

    public void WriteXml(XmlWriter w)
    {
        foreach (var item in Actions)
        {
            w.WriteStartElement("Action");
            w.WriteAttributeString("Type", item.Type);
            w.WriteCData(item.InnerText);                
            w.WriteEndElement();
            w.WriteString("\r\n");
        }
    }

    public void ReadXml(XmlReader r)
    {
        XmlDocument xDoc = new XmlDocument();
        xDoc.Load(r);

        XmlNodeList nodes = xDoc.GetElementsByTagName("Action");
        if (nodes != null && nodes.Count > 0)
        {
            foreach (XmlElement node in nodes)
            {
                Action a = new Action();
                a.Type = node.GetAttribute("Type");
                a.InnerText = node.InnerXml;
                if (a.InnerText != null && a.InnerText.StartsWith("<![CDATA[") && a.InnerText.EndsWith("]]>"))
                    a.InnerText = a.InnerText.Substring("<![CDATA[".Length, a.InnerText.Length - "<![CDATA[]]>".Length);

                Actions.Add(a);
            }
        }
    }
}

public class Action
{
    public String Type { get; set; }
    public String InnerText { get; set; }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文