C# 将类序列化为XML并包含CDATA节时出现问题

C# 将类序列化为XML并包含CDATA节时出现问题,c#,xml,xml-serialization,C#,Xml,Xml Serialization,我有一个被序列化为XML的类,供web服务使用。在这个类实例中,XML必须包含一个CDATA部分,web服务才能读取它,但我不知道如何实现它 XML需要如下所示: <UpdateOrderStatus> <Action>2</Action> <Value> <![CDATA[ <Shipment> &l

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

XML需要如下所示:

<UpdateOrderStatus> 
    <Action>2</Action> 
        <Value> 
            <![CDATA[ 
                <Shipment> 
                    <Header> 
                        <SellerID>
                            ...
             ]]>
         </Value>
 </UpdateOrderStatus>
我看到了一些关于使用的建议:

[XmlElement("node", typeof(XmlCDataSection))]
但这导致了一个例外

我也试过了

 [XmlElement("Value" + "<![CDATA[")]
然而,我没有得到一个例外:

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

异常是由于包含了我以前的serializeToString方法引起的。由于删除CDATA输出是正确的,除了间距问题,但是我还得到了一个名称空间和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>
这将生成以下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>

1.
2012-07-13T14:05:36.6170802-04:00
0
装运头
0
]]>

这有什么帮助吗:

另外,使用该属性时出现了什么异常

--编辑--

您可以尝试添加自定义类,并执行以下操作:

some xml serializable class,
 {
    .......

    [XmlElement("PayLoad", Type=typeof(CDATA))]
    public CDATA PayLoad
    {
       get { return _payLoad; }
       set { _payLoad = value; }
    }
 }


 public class CDATA : IXmlSerializable
 {
    private string text;
    public CDATA()
    {}

    public CDATA(string text)
    {
       this.text = text;
    }

    public string Text
    {
       get { return text; }
    }

    /// <summary>
    /// Interface implementation not used here.
    /// </summary>
    XmlSchema IXmlSerializable.GetSchema()
    {
       return null;
    }

    /// <summary>
    /// Interface implementation, which reads the content of the CDATA tag
    /// </summary>
    void IXmlSerializable.ReadXml(XmlReader reader)
    {
       this.text = reader.ReadElementString();
    }

    /// <summary>
    /// Interface implementation, which writes the CDATA tag to the xml
    /// </summary>
    void IXmlSerializable.WriteXml(XmlWriter writer)
    {
       writer.WriteCData(this.text);
    }
 }
一些xml可序列化类,
{
.......
[XmlElement(“有效负载”,类型=类型(CDATA))]
公共CDATA有效负载
{
获取{return\u payLoad;}
设置{u payLoad=value;}
}
}
公共类CDATA:IXmlSerializable
{
私有字符串文本;
公共CDATA()
{}
公共CDATA(字符串文本)
{
this.text=文本;
}
公共字符串文本
{
获取{返回文本;}
}
/// 
///此处未使用接口实现。
/// 
XmlSchema IXmlSerializable.GetSchema()
{
返回null;
}
/// 
///接口实现,它读取CDATA标记的内容
/// 
void IXmlSerializable.ReadXml(XmlReader)
{
this.text=reader.ReadElementString();
}
/// 
///接口实现,将CDATA标记写入xml
/// 
void IXmlSerializable.WriteXml(XmlWriter编写器)
{
WriteCData(this.text);
}
}

如图所示

将ShipmentInfo实现为
IXmlSerializable
类型将接近您所需要的-请参见下面的示例

public class StackOverflow_11471676
{
    public class UpdateOrderStatus
    {
        public int Action { get; set; }
        public ValueInfo Value { get; set; }
    }
    [XmlType(TypeName = "Shipment")]
    public class ShipmentInfo
    {
        public string Header { get; set; }
        public string Body { get; set; }
    }
    public class ValueInfo : IXmlSerializable
    {
        public ShipmentInfo Shipment { get; set; }
        private XmlSerializer shipmentInfoSerializer = new XmlSerializer(typeof(ShipmentInfo));

        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(XmlReader reader)
        {
            using (MemoryStream ms = new MemoryStream(
                Encoding.UTF8.GetBytes(
                    reader.ReadContentAsString())))
            {
                Shipment = (ShipmentInfo)this.shipmentInfoSerializer.Deserialize(ms);
            }
        }

        public void WriteXml(XmlWriter writer)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                using (XmlWriter innerWriter = XmlWriter.Create(ms, new XmlWriterSettings { OmitXmlDeclaration = true }))
                {
                    shipmentInfoSerializer.Serialize(innerWriter, this.Shipment);
                    innerWriter.Flush();
                    writer.WriteCData(Encoding.UTF8.GetString(ms.ToArray()));
                }
            }
        }
    }
    public static void Test()
    {
        UpdateOrderStatus obj = new UpdateOrderStatus
        {
            Action = 1,
            Value = new ValueInfo
            {
                Shipment = new ShipmentInfo
                {
                    Header = "Shipment header",
                    Body = "Shipment body"
                }
            }
        };

        XmlSerializer xs = new XmlSerializer(typeof(UpdateOrderStatus));
        MemoryStream ms = new MemoryStream();
        xs.Serialize(ms, obj);
        Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
    }
}

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

尝试:

编辑:

另外,请注意,
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());   
        }   
    }

我认为卡洛斯菲盖拉只是给出了一个优雅的回答,但乍一看可能有点难以理解。这里有一个供您考虑的替代方案,您可以分别序列化/反序列化
UpdateOrderStatus
ShipmentInfo

将业务对象类定义为:

    [XmlRoot("UpdateOrderStatus")]
    public class UpdateOrderStatus
    {
        [XmlElement("Action")]
        public int Action { get; set; }

        private String valueField;
        [XmlElement("Value")]
        public XmlCDataSection Value
        {
            get
            {
                XmlDocument xmlDoc = new XmlDocument();
                return xmlDoc.CreateCDataSection(valueField);
            }
            set
            {
                this.valueField = value.Value;
            }
        }

        [XmlIgnore]
        public ShipmentInfo Shipment
        {
            get;
            set;
        }
    }

    [XmlRoot("ShipmentInfo")]
    public class ShipmentInfo
    {
        [XmlElement("Package")]
        public String Package { get; set; }
        [XmlElement("Header")]
        public String Header { get; set; }
    }
请注意,对于
字段,应使用
xmlcatasection
。 以下是测试/辅助功能:

    // Test function
    const string t = @"<UpdateOrderStatus> 
        <Action>2</Action> 
            <Value> 
                <![CDATA[<ShipmentInfo>
      <Package>packageInfo</Package>
      <Header>headerInfo</Header>
    </ShipmentInfo>]]>
             </Value>
    </UpdateOrderStatus>";

    static void Test1()
    {
        UpdateOrderStatus os = Deserialize(t);

        String t2 = XmlUtil.Serialize(os);
    }

    // Helper functions
    static UpdateOrderStatus Deserialize(String str)
    {
        UpdateOrderStatus os = XmlUtil.DeserializeString<UpdateOrderStatus>(str);
        os.Shipment = XmlUtil.DeserializeString<ShipmentInfo>(os.Value.InnerText);
        return os;
    }

    public static class XmlUtil
    {
        public static String Serialize<T>(T o)
        {
            XmlSerializer s = new XmlSerializer(typeof(T)); //, overrides);
            //StringBuilder builder = new StringBuilder();

            MemoryStream ms = new MemoryStream();
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Encoding = Encoding.UTF8;
            settings.Indent = true;
            using (XmlWriter xmlWriter = XmlWriter.Create(ms, settings))
            {
                XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                ns.Add(String.Empty, String.Empty);
                s.Serialize(xmlWriter, o, ns);
            }
            Byte[] bytes = ms.ToArray();
            // discard the BOM part
            Int32 idx = settings.Encoding.GetPreamble().Length;
            return Encoding.UTF8.GetString(bytes, idx, bytes.Length - idx);
        }

        public static T DeserializeString<T>(String content)
        {
            using (TextReader reader = new StringReader(content))
            {
                XmlSerializer s = new XmlSerializer(typeof(T));
                return (T)s.Deserialize(reader);
            }
        }

        ...
    }
//测试函数
常量字符串t=@“
2.
包装信息
校长信息
]]>
";
静态void Test1()
{
UpdateOrderStatus os=反序列化(t);
字符串t2=XmlUtil.Serialize(os);
}
//辅助函数
静态UpdateOrderStatus反序列化(字符串str)
{
UpdateOrderStatus os=XmlUtil.DeserializeString(str);
os.shipping=XmlUtil.DeserializeString(os.Value.InnerText);
返回操作系统;
}
公共静态类XmlUtil
{
公共静态字符串序列化(TO)
{
XmlSerializer s=新的XmlSerializer(typeof(T));/,重写);
//StringBuilder=新的StringBuilder();
MemoryStream ms=新的MemoryStream();
XmlWriterSettings=新的XmlWriterSettings();
settings.Encoding=Encoding.UTF8;
settings.Indent=true;
使用(XmlWriter=XmlWriter.Create(ms,设置))
{
XmlSerializerNamespaces ns=新的XmlSerializerNamespaces();
ns.Add(String.Empty,String.Empty);
s、 序列化(xmlWriter,o,ns);
}
Byte[]bytes=ms.ToArray();
//放弃BOM表零件
Int32 idx=settings.Encoding.getPremission().Length;
返回Encoding.UTF8.GetString(bytes,idx,bytes.Length-idx);
}
公共静态T反序列化字符串(字符串内容)
{
使用(TextReader=新的StringReader(内容))
{
XmlSerializer s=新的XmlSerializer(typeof(T));
返回(T)s.反序列化(读取器);
}
}
...
}

下面的示例仅在定义了架构的结构并且您没有选择修改架构时出现

反序列化/序列化[xmltext]值时,很难将文本保存在
CDATA[]
随函附上您可以使用compiletransform按原样获取
xml
中的
CDATA
值,但是
CDATA
一旦在C中反序列化并加载到内存中就会丢失

这是最简单的方法之一

  • 反序列化/序列化
  • 一旦导出了最终的xml输出。最后的xml可以是 转换为字符串并按如下所示进行分析,并返回为 字符串将
    CDATA
    嵌入test1值
  • string xml=“@##@!#!#!@#!@%$%@#$%#;
    xns=@;
    XDocument doc=XDocument.Parse(xml);
    string xmlString=string.Empty;
    var coll=来自文档子体中的查询(ns+“test1”)
    选择查询;
    foreach(coll中的var值){
    ReplaceNodes(新的XCData(value.value));
    }
    doc.save(“test.xml”);//将doc.tostring转换为(
    
    some xml serializable class,
     {
        .......
    
        [XmlElement("PayLoad", Type=typeof(CDATA))]
        public CDATA PayLoad
        {
           get { return _payLoad; }
           set { _payLoad = value; }
        }
     }
    
    
     public class CDATA : IXmlSerializable
     {
        private string text;
        public CDATA()
        {}
    
        public CDATA(string text)
        {
           this.text = text;
        }
    
        public string Text
        {
           get { return text; }
        }
    
        /// <summary>
        /// Interface implementation not used here.
        /// </summary>
        XmlSchema IXmlSerializable.GetSchema()
        {
           return null;
        }
    
        /// <summary>
        /// Interface implementation, which reads the content of the CDATA tag
        /// </summary>
        void IXmlSerializable.ReadXml(XmlReader reader)
        {
           this.text = reader.ReadElementString();
        }
    
        /// <summary>
        /// Interface implementation, which writes the CDATA tag to the xml
        /// </summary>
        void IXmlSerializable.WriteXml(XmlWriter writer)
        {
           writer.WriteCData(this.text);
        }
     }
    
    public class StackOverflow_11471676
    {
        public class UpdateOrderStatus
        {
            public int Action { get; set; }
            public ValueInfo Value { get; set; }
        }
        [XmlType(TypeName = "Shipment")]
        public class ShipmentInfo
        {
            public string Header { get; set; }
            public string Body { get; set; }
        }
        public class ValueInfo : IXmlSerializable
        {
            public ShipmentInfo Shipment { get; set; }
            private XmlSerializer shipmentInfoSerializer = new XmlSerializer(typeof(ShipmentInfo));
    
            public System.Xml.Schema.XmlSchema GetSchema()
            {
                return null;
            }
    
            public void ReadXml(XmlReader reader)
            {
                using (MemoryStream ms = new MemoryStream(
                    Encoding.UTF8.GetBytes(
                        reader.ReadContentAsString())))
                {
                    Shipment = (ShipmentInfo)this.shipmentInfoSerializer.Deserialize(ms);
                }
            }
    
            public void WriteXml(XmlWriter writer)
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    using (XmlWriter innerWriter = XmlWriter.Create(ms, new XmlWriterSettings { OmitXmlDeclaration = true }))
                    {
                        shipmentInfoSerializer.Serialize(innerWriter, this.Shipment);
                        innerWriter.Flush();
                        writer.WriteCData(Encoding.UTF8.GetString(ms.ToArray()));
                    }
                }
            }
        }
        public static void Test()
        {
            UpdateOrderStatus obj = new UpdateOrderStatus
            {
                Action = 1,
                Value = new ValueInfo
                {
                    Shipment = new ShipmentInfo
                    {
                        Header = "Shipment header",
                        Body = "Shipment body"
                    }
                }
            };
    
            XmlSerializer xs = new XmlSerializer(typeof(UpdateOrderStatus));
            MemoryStream ms = new MemoryStream();
            xs.Serialize(ms, obj);
            Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
        }
    }
    
    settings.Encoding = new Utf8Encoding(false);
    
        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());   
            }   
        }
    
        [XmlRoot("UpdateOrderStatus")]
        public class UpdateOrderStatus
        {
            [XmlElement("Action")]
            public int Action { get; set; }
    
            private String valueField;
            [XmlElement("Value")]
            public XmlCDataSection Value
            {
                get
                {
                    XmlDocument xmlDoc = new XmlDocument();
                    return xmlDoc.CreateCDataSection(valueField);
                }
                set
                {
                    this.valueField = value.Value;
                }
            }
    
            [XmlIgnore]
            public ShipmentInfo Shipment
            {
                get;
                set;
            }
        }
    
        [XmlRoot("ShipmentInfo")]
        public class ShipmentInfo
        {
            [XmlElement("Package")]
            public String Package { get; set; }
            [XmlElement("Header")]
            public String Header { get; set; }
        }
    
        // Test function
        const string t = @"<UpdateOrderStatus> 
            <Action>2</Action> 
                <Value> 
                    <![CDATA[<ShipmentInfo>
          <Package>packageInfo</Package>
          <Header>headerInfo</Header>
        </ShipmentInfo>]]>
                 </Value>
        </UpdateOrderStatus>";
    
        static void Test1()
        {
            UpdateOrderStatus os = Deserialize(t);
    
            String t2 = XmlUtil.Serialize(os);
        }
    
        // Helper functions
        static UpdateOrderStatus Deserialize(String str)
        {
            UpdateOrderStatus os = XmlUtil.DeserializeString<UpdateOrderStatus>(str);
            os.Shipment = XmlUtil.DeserializeString<ShipmentInfo>(os.Value.InnerText);
            return os;
        }
    
        public static class XmlUtil
        {
            public static String Serialize<T>(T o)
            {
                XmlSerializer s = new XmlSerializer(typeof(T)); //, overrides);
                //StringBuilder builder = new StringBuilder();
    
                MemoryStream ms = new MemoryStream();
                XmlWriterSettings settings = new XmlWriterSettings();
                settings.Encoding = Encoding.UTF8;
                settings.Indent = true;
                using (XmlWriter xmlWriter = XmlWriter.Create(ms, settings))
                {
                    XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                    ns.Add(String.Empty, String.Empty);
                    s.Serialize(xmlWriter, o, ns);
                }
                Byte[] bytes = ms.ToArray();
                // discard the BOM part
                Int32 idx = settings.Encoding.GetPreamble().Length;
                return Encoding.UTF8.GetString(bytes, idx, bytes.Length - idx);
            }
    
            public static T DeserializeString<T>(String content)
            {
                using (TextReader reader = new StringReader(content))
                {
                    XmlSerializer s = new XmlSerializer(typeof(T));
                    return (T)s.Deserialize(reader);
                }
            }
    
            ...
        }