问题
Is it possible to store the original XML element in a C# class, for example?
Original 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="" />
}
}
I understand I could deserialize the class again but some XML objects are unknown at design time.
回答1:
If you really need to capture everything about the <data /> element including the element name and namespace itself into a string literal, you will need to implement IXmlSerializable and serialize your Data type manually. For instance, here is a prototype implementation:
[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;
}
}
}
Notes:
When reading, the complete XML is loaded into an
XElementmember which can be queried using LINQ to XML. As a result the original formatting may get lost.IXmlSerializableis tricky to implement correctly. See Proper way to implement IXmlSerializable? and How to Implement IXmlSerializable Correctly for some tips on how to do it.The known properties
Someattributea,SomeattributebandSomeattributecnow become surrogate lookups into the underlyingXElement.
Working .Net fiddle here.
If, on the other hand, you only need to capture unknown elements, attributes and text content, you can use [XmlAnyAttribute], [XmlAnyElement] and [XmlText] (the first two of which are suggested in this answer to XmlSerializer equivalent of IExtensibleDataObject by Marc Gravell). This approach results in a much simpler version of 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; }
}
Working .Net fiddle #2 here.
来源:https://stackoverflow.com/questions/50304153/xmlserializer-to-c-sharp-object-store-original-xml-element