c# - Xmlserializer 到 C# 对象,存储原始 XML 元素
问题描述
例如,是否可以将原始 XML 元素存储在 C# 类中?
原始 XML:
<data someattributea="" someattributeb="" someattributec="" />
C#
using System;
using System.Xml.Serialization;
using System.Collections.Generic;
namespace Xml2CSharp
{
[XmlRoot(ElementName="data")]
public class Data {
[XmlAttribute(AttributeName="someattributea")]
public string Someattributea { get; set; }
[XmlAttribute(AttributeName="someattributeb")]
public string Someattributeb { get; set; }
[XmlAttribute(AttributeName="someattributec")]
public string Someattributec { get; set; }
public sourceXML { get; set; } //this would return <data someattributea="" someattributeb="" someattributec="" />
}
}
我知道我可以再次反序列化该类,但某些 XML 对象在设计时是未知的。
解决方案
如果您确实需要将有关<data />
元素的所有内容(包括元素名称和命名空间本身)捕获到字符串文字中,则需要手动实现IXmlSerializable
和序列化您的类型。Data
例如,这是一个原型实现:
[XmlRoot(ElementName = ElementName)]
public class Data : IXmlSerializable
{
public const string ElementName = "data";
XElement element = new XElement((XName)ElementName);
public string Someattributea
{
get { return (string)element.Attribute("someattributea"); }
set { element.SetAttribute("someattributea", value); }
}
public string Someattributeb
{
get { return (string)element.Attribute("someattributeb"); }
set { element.SetAttribute("someattributeb", value); }
}
public string Someattributec
{
get { return (string)element.Attribute("someattributec"); }
set { element.SetAttribute("someattributec", value); }
}
public string SourceXML
{
get
{
return element.ToString();
}
set
{
if (value == null)
throw new ArgumentNullException();
element = XElement.Parse(value);
}
}
#region IXmlSerializable Members
public XmlSchema GetSchema() { return null; }
public void ReadXml(XmlReader reader)
{
reader.MoveToContent();
element = (XElement)XNode.ReadFrom(reader);
}
public void WriteXml(XmlWriter writer)
{
foreach (var attr in element.Attributes())
writer.WriteAttributeString(attr.Name.LocalName, attr.Name.NamespaceName, attr.Value);
foreach (var child in element.Elements())
child.WriteTo(writer);
}
#endregion
}
public static class XElementExtensions
{
public static void SetAttribute(this XElement element, XName attributeName, string value)
{
var attr = element.Attribute(attributeName);
if (value == null)
{
if (attr != null)
attr.Remove();
}
else
{
if (attr == null)
element.Add(new XAttribute(attributeName, value));
else
attr.Value = value;
}
}
}
笔记:
读取时,完整的 XML 被加载到
XElement
可以使用LINQ to XML查询的成员中。因此,原始格式可能会丢失。IXmlSerializable
很难正确实施。请参阅实现 IXmlSerializable 的正确方法?以及如何正确实现 IXmlSerializable以获取有关如何执行此操作的一些提示。已知的属性
Someattributea
,Someattributeb
现在Someattributec
成为底层的代理查找XElement
。
在这里工作.Net 小提琴。
另一方面,如果您只需要捕获未知元素、属性和文本内容,则可以使用[XmlAnyAttribute]
,[XmlAnyElement]
和[XmlText]
(其中前两个是Marc Gravell对XmlSerializer 等效的 IExtensibleDataObject的回答中建议的)。这种方法产生了一个更简单的版本:Data
[XmlRoot(ElementName = "data")]
public class Data
{
[XmlAttribute(AttributeName = "someattributea")]
public string Someattributea { get; set; }
[XmlAttribute(AttributeName = "someattributeb")]
public string Someattributeb { get; set; }
[XmlAttribute(AttributeName = "someattributec")]
public string Someattributec { get; set; }
[XmlAnyAttribute]
public XmlAttribute[] Attributes { get; set; }
[XmlAnyElement]
[XmlText] // Captures mixed content at the root level as well as child elements.
public XmlNode[] ChildNodes { get; set; }
}
工作 .Net fiddle #2 here。