您可以使用[XmlText]
属性来指示属性应序列化为文本而不是标记,例如:
[XmlRoot("root")]
public class Root
{
[XmlText]
public string Value { get; set; }
[XmlElement("info2")]
public Info2 Info2 { get; set; }
}
但是,如果您用问题中所示的CDATA内容填充Root.Value
,则生成的XML虽然格式良好,但其字符将单独转义,而不是作为CDATA:
<root><info>
<number>12</number>
<files>1</files>
</info> <Info2><prop1> prop1 </prop1></Info2></root>
演示小提琴#1here.
这种形式的XML转义在语义上等同于CDATA转义,但如果出于某种原因您对CDATA转义require,您可以使用remarks for XmlTextAttribute
中提到的以下功能.
XmlTextAttribute
还可以应用于返回XmlNode
或XmlNode
对象数组的字段.
诀窍是引入一个代理XmlNode []
属性,该属性返回封装在XmlNode
数组中包含的XmlCDataSection
对象中的所需文本内容.如果我们进一步假设内容是序列化名为Info
的其他属性的结果,您的数据模型可能如下所示:
[XmlRoot("root")]
public class Root
{
[XmlIgnore]
public Info Info { get; set; }
//https://learn.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmltextattribute?view=net-8.0
//The XmlTextAttribute can also be applied to a field that returns an XmlNode or an array of XmlNode objects.
[XmlText]
public XmlNode [] XmlValue
{
get => new XmlNode [] { new XmlDocument().CreateCDataSection(Info.GetXml(indent : true, omitStandardNamespaces : true, omitXmlDeclaration : true)) };
set
{
var xml = string.Concat(value?.Cast<XmlCharacterData>().Select(c => c.Value)).Trim();
if (!string.IsNullOrEmpty(xml))
Info = xml.LoadFromXml<Info>();
}
}
[XmlElement("info2")]
public Info2 Info2 { get; set; }
}
[XmlRoot("info")]
public class Info
{
[XmlElement("number")] public int Number { get; set; }
[XmlElement("files")] public int Files { get; set; }
}
public class Info2
{
[XmlElement("prop1")]
public string Prop1 { get; set; }
}
它使用以下扩展方法:
public static partial class XmlSerializationHelper
{
public static T? LoadFromXml<T>(this string xmlString, XmlSerializer? serializer = null)
{
using (var reader = new StringReader(xmlString))
return (T?)(serializer ?? new(typeof(T))).Deserialize(reader);
}
public static string GetXml<T>(this T? obj, XmlSerializer? serializer = null, bool indent = true, bool omitStandardNamespaces = false, bool omitXmlDeclaration = false)
{
XmlSerializerNamespaces? ns = null;
if (omitStandardNamespaces)
{
ns = new ();
ns.Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
}
using var textWriter = new StringWriter();
var settings = new XmlWriterSettings() { Indent = indent, OmitXmlDeclaration = omitXmlDeclaration };
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
(serializer ?? new(obj?.GetType() ?? typeof(T))).Serialize(xmlWriter, obj, ns);
return textWriter.ToString();
}
}
此版本的Root
在与XmlSerializer
序列化时会生成以下XML:
<root><![CDATA[<info>
<number>1</number>
<files>1</files>
</info>]]><info2><prop1> prop1 </prop1></info2></root>
演示小提琴#2here.
备注:
你的<root>
元素等于100.如XmlWriterSettings.Indent
的文档中所述
只要元素不包含混合内容,元素就会缩进.一旦调用了WriteString或WriteWhite方法以写出混合元素内容,则为the XmlWriter stops indenting.一旦混合内容元素关闭,缩进就会继续.
因此,似乎不可能获得您的.NET XmlWriter
问题中所示的精确缩进.因为这样的空格是not significant,所以这对任何接收系统都不重要,但如果是这样的话,您可能需要采用不同的XML框架或编写您自己的XmlWriter
子类.
使用正则表达式进行后处理可能是另一种 Select .
出于某种原因,如果我声明XmlValue
属性返回单个XmlNode
,例如
[XmlText]
public XmlNode XmlValue { get => new XmlDocument().CreateCDataSection(Value); set => Value = value?.Value; }
然后,在.NET8中,XmlSerializer
构造函数将失败并抛出异常,尽管有文档记录它可以工作:
System.InvalidOperationException:无法序列化类型为System.Xml.XmlNode的成员‘XmlValue’.XmlAttribute/XmlText不能用于编码复杂类型.
这就是我使用数组属性的原因.
小提琴here不及格.
[XmlText]
解决方案似乎比100中建议的实现IXmlSerializable
简单得多.