如何防止XmlSerialzer转义"nested XML"?
How to prevent XmlSerialzer from escaping "nested XML"?
我正在使用 XmlSerializer 序列化/反序列化复杂对象。一个 属性 包含一个 XML 字符串,应该在不反序列化的情况下写入字符串 属性。
示例(可在 LinqPad 中执行):
[XmlRoot("RootObject")]
[Serializable]
public class RootClass
{
[XmlArray("SubObjects")]
[XmlArrayItem("SubObject")]
public SubClass[] SubObjecs { get; set;}
}
[Serializable]
public class SubClass
{
[XmlElement("XmlConfiguration")]
public string XmlConfiguration { get; set;}
}
void Main()
{
var obj = new RootClass()
{
SubObjecs = new[]
{
new SubClass { XmlConfiguration = "<ConfigurationX>SomeConfiguration1</ConfigurationX>" },
new SubClass { XmlConfiguration = "<ConfigurationY>SomeConfiguration2</ConfigurationY>" }
}
};
var serializer = new XmlSerializer(typeof(RootClass));
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, obj);
stream.Position = 0;
Console.WriteLine(Encoding.UTF8.GetString(stream.GetBuffer()));
}
}
示例的输出是:
<?xml version="1.0"?>
<RootObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SubObjects>
<SubObject>
<XmlConfiguration><ConfigurationX>SomeConfiguration1</ConfigurationX></XmlConfiguration>
</SubObject>
<SubObject>
<XmlConfiguration><ConfigurationY>SomeConfiguration2</ConfigurationY></XmlConfiguration>
</SubObject>
</SubObjects>
</RootObject>
XML 是一个配置文件,有时以编程方式编写,但主要由人编写/修改。因此 XmlConfiguration
中的 XML 不应包含转义字符。
问题:
是否可以防止 XmlSerializer 转义“<”和“>”字符?如果没有,是否可以使用另一个序列化程序?
一个可行的选项是 XmlWriter.WriteRaw。但是,如果可能的话,我会避免这种不可靠且不易维护的解决方案。
我在这里发现了一个类似的问题:How to prevent XmlSerializer from escaping < and > characters。但是那个问题与 !CDATA[[Content]] 有关,我的问题没有答案。
正如上面在 dbc 的评论中提到的,有一个使用 XmlAnyElement
属性的解决方案,如下所述:
我找到了一个混合了 XmlSerializer
和 XmlWriter.WriteRaw
的解决方案。当实现IXmlSerializable
时,可以控制XmlSerializer
的序列化过程。 Therfore IXmlSerializable 必须只为需要特殊处理的 class 实现(这对我来说没问题):
[Serializable]
public class SubClass : IXmlSerializable
{
[XmlElement("XmlConfiguration")]
public string XmlConfiguration { get; set; }
public void WriteXml(XmlWriter writer)
{
writer.WriteStartElement("XmlConfiguration");
writer.WriteRaw(XmlConfiguration);
writer.WriteEndElement();
}
public void ReadXml(XmlReader reader)
{
reader.ReadToDescendant("XmlConfiguration");
XmlConfiguration = reader.ReadInnerXml();
reader.ReadEndElement();
}
public XmlSchema GetSchema()
{
return (null);
}
}
如果您需要 CDATA 封装,您可以使用 XmlCDataSection Class。您关注 class 作为 xml 元素的类型。您可以根据需要为每种不同类型的元素更改名称或属性。
public class XmlConfiguration //Or any other class name.
{
[XmlAttribute("attr1")]
public string Attr1 { get; set; } //You don't need this but use if you need attribute.
[XmlAttribute("attr2")]
public string Attr2 { get; set; } //Or second one.
[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;
}
}
}
我找到了这个答案 here。检查 link 以获得完整的讨论。
我正在使用 XmlSerializer 序列化/反序列化复杂对象。一个 属性 包含一个 XML 字符串,应该在不反序列化的情况下写入字符串 属性。
示例(可在 LinqPad 中执行):
[XmlRoot("RootObject")]
[Serializable]
public class RootClass
{
[XmlArray("SubObjects")]
[XmlArrayItem("SubObject")]
public SubClass[] SubObjecs { get; set;}
}
[Serializable]
public class SubClass
{
[XmlElement("XmlConfiguration")]
public string XmlConfiguration { get; set;}
}
void Main()
{
var obj = new RootClass()
{
SubObjecs = new[]
{
new SubClass { XmlConfiguration = "<ConfigurationX>SomeConfiguration1</ConfigurationX>" },
new SubClass { XmlConfiguration = "<ConfigurationY>SomeConfiguration2</ConfigurationY>" }
}
};
var serializer = new XmlSerializer(typeof(RootClass));
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, obj);
stream.Position = 0;
Console.WriteLine(Encoding.UTF8.GetString(stream.GetBuffer()));
}
}
示例的输出是:
<?xml version="1.0"?>
<RootObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SubObjects>
<SubObject>
<XmlConfiguration><ConfigurationX>SomeConfiguration1</ConfigurationX></XmlConfiguration>
</SubObject>
<SubObject>
<XmlConfiguration><ConfigurationY>SomeConfiguration2</ConfigurationY></XmlConfiguration>
</SubObject>
</SubObjects>
</RootObject>
XML 是一个配置文件,有时以编程方式编写,但主要由人编写/修改。因此 XmlConfiguration
中的 XML 不应包含转义字符。
问题: 是否可以防止 XmlSerializer 转义“<”和“>”字符?如果没有,是否可以使用另一个序列化程序?
一个可行的选项是 XmlWriter.WriteRaw。但是,如果可能的话,我会避免这种不可靠且不易维护的解决方案。
我在这里发现了一个类似的问题:How to prevent XmlSerializer from escaping < and > characters。但是那个问题与 !CDATA[[Content]] 有关,我的问题没有答案。
正如上面在 dbc 的评论中提到的,有一个使用 XmlAnyElement
属性的解决方案,如下所述:
我找到了一个混合了 XmlSerializer
和 XmlWriter.WriteRaw
的解决方案。当实现IXmlSerializable
时,可以控制XmlSerializer
的序列化过程。 Therfore IXmlSerializable 必须只为需要特殊处理的 class 实现(这对我来说没问题):
[Serializable]
public class SubClass : IXmlSerializable
{
[XmlElement("XmlConfiguration")]
public string XmlConfiguration { get; set; }
public void WriteXml(XmlWriter writer)
{
writer.WriteStartElement("XmlConfiguration");
writer.WriteRaw(XmlConfiguration);
writer.WriteEndElement();
}
public void ReadXml(XmlReader reader)
{
reader.ReadToDescendant("XmlConfiguration");
XmlConfiguration = reader.ReadInnerXml();
reader.ReadEndElement();
}
public XmlSchema GetSchema()
{
return (null);
}
}
如果您需要 CDATA 封装,您可以使用 XmlCDataSection Class。您关注 class 作为 xml 元素的类型。您可以根据需要为每种不同类型的元素更改名称或属性。
public class XmlConfiguration //Or any other class name.
{
[XmlAttribute("attr1")]
public string Attr1 { get; set; } //You don't need this but use if you need attribute.
[XmlAttribute("attr2")]
public string Attr2 { get; set; } //Or second one.
[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;
}
}
}
我找到了这个答案 here。检查 link 以获得完整的讨论。