c# - 将类序列化为 XML 并包含 CDATA 部分时出现问题

标签 c# xml xml-serialization

我有一个序列化为 XML 以供 Web 服务使用的类。在这个类实例中,XML 必须包含一个 CDATA 部分,以便 Web 服务读取它,但我不知道如何实现它。

XML 需要看起来像:

<UpdateOrderStatus> 
    <Action>2</Action> 
        <Value> 
            <![CDATA[ 
                <Shipment> 
                    <Header> 
                        <SellerID>
                            ...
             ]]>
         </Value>
 </UpdateOrderStatus>

我能够生成适当的 XML,CDATA 部分除外。

我的类结构如下:

public class UpdateOrderStatus
{
    public int Action { get; set; }


    public ValueInfo Value { get; set; }

    public UpdateOrderStatus()
    {
        Value = new ValueInfo();
    }


    public class ValueInfo
    {
        public ShipmentInfo Shipment { get; set; }

        public ValueInfo()
        {
            Shipment = new ShipmentInfo();
        }

        public class ShipmentInfo
        {
            public PackageListInfo PackageList { get; set; }
            public HeaderInfo Header { get; set; }
            public ShipmentInfo()
            {
                PackageList = new PackageListInfo();
                Header = new HeaderInfo();
            }

         ....

我看到了一些关于使用的建议:

[XmlElement("node", typeof(XmlCDataSection))]

但这会导致异常

我也试过

 [XmlElement("Value" + "<![CDATA[")]

但是生成的 XML 显示不正确

 <Value_x003C__x0021__x005B_CDATA_x005B_>
 ....
 </Value_x003C__x0021__x005B_CDATA_x005B_>

任何人都可以告诉我我做错了什么,或者我需要去哪里吗?

--编辑--

使每个 carlosfigueira 的 shipmentInfo 可序列化在大多数情况下都有效,但是我得到额外的 ?结果 XML 中的字符(有关详细信息,请参阅帖子 Writing an XML fragment using XmlWriterSettings and XmlSerializer is giving an extra character)

因此,我将 Write XML 方法更改为:

public void WriteXml(XmlWriter writer)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                ns.Add("", "");

                XmlWriterSettings settings = new XmlWriterSettings();

                settings.OmitXmlDeclaration = true;
                settings.Encoding = new UnicodeEncoding(bigEndian: false, byteOrderMark: false);
                settings.Indent = true;

                using (XmlWriter innerWriter = XmlWriter.Create(ms, settings))
                {
                    shipmentInfoSerializer.Serialize(innerWriter, this.Shipment,ns);
                    innerWriter.Flush();
                    writer.WriteCData(Encoding.UTF8.GetString(ms.ToArray()));
                }
            }
        }

但是我没有得到异常:

System.InvalidOperationException: There was an error generating the XML document. ---> System.ArgumentException: '.', hexadecimal
value 0x00, is an invalid character.

--编辑--

该异常是由于包含了我之前的 serializeToString 方法引起的。由于删除 CDATA 输出是正确的,除了间距问题,但我也得到了一个 namespace 和 xml 声明,它们应该由指定的 XML 设置删除。输出是:

<?xml version="1.0"?>
<UpdateOrderStatus xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Action>1</Action>
  <Value><![CDATA[< S h i p m e n t I n f o >
     < P a c k a g e L i s t >
         < P a c k a g e >
             < S h i p D a t e > 2 0 1 2 - 0 7 - 1 3 T 1 1 : 5 8 : 5 1 . 0 9 2 5 6 1 5 - 0 4 : 0 0 < / S h i p D a t e >
             < I t e m L i s t >
                 < I t e m >
                     < S h i p p e d Q t y > 0 < / S h i p p e d Q t y >
                 < / I t e m >
             < / I t e m L i s t >
         < / P a c k a g e >
     < / P a c k a g e L i s t >
     < H e a d e r >
         < S e l l e r I d > S h i p m e n t   h e a d e r < / S e l l e r I d >
         < S O N u m b e r > 0 < / S O N u m b e r >
     < / H e a d e r >
 < / S h i p m e n t I n f o > ]]></Value>
</UpdateOrderStatus>

有没有使用新类避免 BOM 的想法?

--编辑 3 -- 成功!

我已经实现了下面建议的更改,现在有以下编写器类和测试方法:

 UpdateOrderStatus obj = new UpdateOrderStatus();

        obj.Action = 1;
        obj.Value = new UpdateOrderStatus.ValueInfo();
        obj.Value.Shipment = new UpdateOrderStatus.ValueInfo.ShipmentInfo();
        obj.Value.Shipment.Header.SellerId = "Shipment header";
        obj.Value.Shipment.PackageList = new UpdateOrderStatus.ValueInfo.ShipmentInfo.PackageListInfo();
        obj.Value.Shipment.PackageList.Package = new UpdateOrderStatus.ValueInfo.ShipmentInfo.PackageListInfo.PackageInfo();
        obj.Value.Shipment.PackageList.Package.ShipDate = DateTime.Now;



        XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
        ns.Add("", "");
        XmlWriterSettings settings = new XmlWriterSettings();
        settings.OmitXmlDeclaration = true;
        settings.Encoding = new UTF8Encoding(false);
        settings.Indent = true;
        XmlSerializer xs = new XmlSerializer(typeof(UpdateOrderStatus));
        MemoryStream ms = new MemoryStream();


        XmlWriter writer = XmlWriter.Create(ms, settings);
        xs.Serialize(writer, obj, ns);
        Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
    }


public void WriteXml(XmlWriter writer)
        {

            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
            ns.Add("", "");

            XmlWriterSettings settings = new XmlWriterSettings();

            settings.OmitXmlDeclaration = true;
            settings.Indent = true;

            StringBuilder sb = new StringBuilder();
            using (XmlWriter innerWriter = XmlWriter.Create(sb, settings))
            {
                shipmentInfoSerializer.Serialize(innerWriter, this.Shipment, ns);
                innerWriter.Flush();
                writer.WriteCData(sb.ToString());
            }   
        }

这会产生以下 XML:

<UpdateOrderStatus>
  <Action>1</Action>
  <Value><![CDATA[<ShipmentInfo>
  <PackageList>
    <Package>
      <ShipDate>2012-07-13T14:05:36.6170802-04:00</ShipDate>
      <ItemList>
        <Item>
          <ShippedQty>0</ShippedQty>
        </Item>
      </ItemList>
    </Package>
  </PackageList>
  <Header>
    <SellerId>Shipment header</SellerId>
    <SONumber>0</SONumber>
  </Header>
</ShipmentInfo>]]></Value>
</UpdateOrderStatus>

最佳答案

针对您在编辑后看到的“空格”,这是因为您使用的编码(Unicode,每个字符 2 个字节)。

尝试:

settings.Encoding = new Utf8Encoding(false);

编辑:

另请注意,MemoryStream 的格式不一定是有效的 UTF-8 编码字符串!您可以使用 StringBuilder 而不是 MemoryStream 来创建您的内部编写器。

    public void WriteXml(XmlWriter writer)   
    {   
        XmlSerializerNamespaces ns = new XmlSerializerNamespaces();   
        ns.Add("", "");   

        XmlWriterSettings settings = new XmlWriterSettings();   

        settings.OmitXmlDeclaration = true;   
        settings.Indent = true;   

        StringBuilder sb = new StringBuilder();
        using (XmlWriter innerWriter = XmlWriter.Create(sb, settings))   
        {   
            shipmentInfoSerializer.Serialize(innerWriter, this.Shipment,ns);   
            innerWriter.Flush();   
            writer.WriteCData(sb.ToString());   
        }   
    }

关于c# - 将类序列化为 XML 并包含 CDATA 部分时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11471676/

相关文章:

java - Android开发中类与xml布局的通信

c# - XmlSerialization - 读取结束元素标签?

c# - 使用 IDbConnection/IDbTransaction 安全吗?

c# - 我收到错误 "System.Array does not contain a definition for LastWriteTime"

java - 使用 XPath 读取站点地图

c++ - 没有托管代码的 xml 序列化?

.net - 使用 DataContractSerializer 序列化没有命名空间的对象

c# - 在哪里存储数据以避免数据库命中?

c# - 单选按钮值为空

java - 具有大量实体的规范和 XML 解析 -> 内存不足错误