如何使用注释从类的属性值派生xml元素名称?

我有具有ID和值以及名称的属性。 我可以使用XmlElement / XmlArray C#注释代表所有具有单个类的人吗? 我想从类属性名称派生xml元素名称 ;

我的class级看起来像:

public class Property { public string name; //could be enum public int id; public string value; } 

例如:

 new Property("property1name",2,"testvalue"); new Property("property2name",10,"anothervalue"); 

我想要xml看起来像:

 2testvalue 10anothervalue 

而不是通常的

 property1name2testvalue property2name10anothervalue 

换句话说,xmlelement的名称来自类Property的属性名称

更新

这里是一个快速适应处理你的Property类。 首先,实现IXmlSerializableList子类:

 public interface IHasElementName { string ElementName { get; set; } } public class XmlNamedElementList : List, IXmlSerializable where T : IHasXmlElementName { // https://msdn.microsoft.com/en-us/library/System.Xml.Serialization.XmlSerializer%28v=vs.110%29.aspx // Any serializer created with the "XmlSerializer(typeof(T), rootAttribute)" must be cached // to avoid resource & memory leaks. class ValueSerializerCache { // By using a nested class with a static constructor, we defer generation of the XmlSerializer until it's actually required. static ValueSerializerCache() { var rootAttribute = new XmlRootAttribute(); rootAttribute.ElementName = ValueTypeName; rootAttribute.Namespace = ValueTypeNamespace; serializer = new XmlSerializer(typeof(T), rootAttribute); } static readonly XmlSerializer serializer; internal static XmlSerializer Serializer { get { return serializer; } } } static string ValueTypeName { get { return typeof(T).DefaultXmlElementName(); } } static string ValueTypeNamespace { get { return typeof(T).DefaultXmlElementNamespace(); } } #region IXmlSerializable Members XmlSchema IXmlSerializable.GetSchema() { return null; } void IXmlSerializable.ReadXml(XmlReader reader) { if (reader.IsEmptyElement) { reader.Read(); return; } var typeName = ValueTypeName; reader.ReadStartElement(); // Advance to the first sub element of the list element. while (reader.NodeType == XmlNodeType.Element) { var name = reader.Name; using (var subReader = reader.ReadSubtree()) { var doc = XDocument.Load(subReader); if (doc != null && doc.Root != null) { doc.Root.Name = doc.Root.Name.Namespace + typeName; using (var docReader = doc.CreateReader()) { var obj = ValueSerializerCache.Serializer.Deserialize(docReader); if (obj != null) { T value = (T)obj; value.ElementName = XmlConvert.DecodeName(name); Add(value); } } } } // Move past the end of item element reader.Read(); } // Move past the end of the list element reader.ReadEndElement(); } void IXmlSerializable.WriteXml(XmlWriter writer) { foreach (var value in this) { XDocument doc = new XDocument(); using (var subWriter = doc.CreateWriter()) { // write xml into the writer ValueSerializerCache.Serializer.Serialize(subWriter, value); } if (doc.Root == null) continue; doc.Root.Name = doc.Root.Name.Namespace + XmlConvert.EncodeName(value.ElementName); // Remove redundant namespaces. foreach (var attr in doc.Root.Attributes().ToList()) { if (!attr.IsNamespaceDeclaration || string.IsNullOrEmpty(attr.Value)) continue; var prefix = writer.LookupPrefix(attr.Value); if ((prefix == attr.Name.LocalName) || (prefix == string.Empty && attr.Name == "xmlns")) attr.Remove(); } doc.Root.WriteTo(writer); } } #endregion } public static class XmlSerializationHelper { static Attribute GetCustomAttribute(MemberInfo element, Type attributeType) { return Attribute.GetCustomAttribute(element, attributeType); } static T GetCustomAttribute(MemberInfo element) where T : Attribute { return (T)GetCustomAttribute(element, typeof(T)); } public static string DefaultXmlElementName(this Type type) { var xmlType = GetCustomAttribute(type); if (xmlType != null && !string.IsNullOrEmpty(xmlType.TypeName)) return xmlType.TypeName; var xmlRoot = GetCustomAttribute(type); if (xmlRoot != null && !string.IsNullOrEmpty(xmlRoot.ElementName)) return xmlRoot.ElementName; return type.Name; } public static string DefaultXmlElementNamespace(this Type type) { var xmlType = GetCustomAttribute(type); if (xmlType != null && !string.IsNullOrEmpty(xmlType.Namespace)) return xmlType.Namespace; var xmlRoot = GetCustomAttribute(type); if (xmlRoot != null && !string.IsNullOrEmpty(xmlRoot.Namespace)) return xmlRoot.Namespace; return string.Empty; } public static string GetXml(this T obj) { return GetXml(obj, false); } public static string GetXml(this T obj, bool omitNamespace) { return GetXml(obj, new XmlSerializer(obj.GetType()), omitNamespace); } public static string GetXml(this T obj, XmlSerializer serializer) { return GetXml(obj, serializer, false); } public static string GetXml(T obj, XmlSerializer serializer, bool omitStandardNamespaces) { XmlSerializerNamespaces ns = null; if (omitStandardNamespaces) { ns = new XmlSerializerNamespaces(); ns.Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines. } return GetXml(obj, serializer, ns); } public static string GetXml(T obj, XmlSerializerNamespaces ns) { return GetXml(obj, new XmlSerializer(obj.GetType()), ns); } public static string GetXml(T obj, XmlSerializer serializer, XmlSerializerNamespaces ns) { using (var textWriter = new StringWriter()) { XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; // For cosmetic purposes. settings.IndentChars = " "; // For cosmetic purposes. using (var xmlWriter = XmlWriter.Create(textWriter, settings)) { if (ns != null) serializer.Serialize(xmlWriter, obj, ns); else serializer.Serialize(xmlWriter, obj); } return textWriter.ToString(); } } } 

并使用它像:

 public class Property : IHasElementName { public Property() { } public Property(string name, int id, string value) { this.name = name; this.id = id; this.value = value; } [XmlIgnore] public string name; //could be enum public int id; public string value; #region IHasElementName Members [XmlIgnore] string IHasElementName.ElementName { get { return name; } set { name = value; } } #endregion } public class RootObject { public RootObject() { this.Properties = new XmlNamedElementList(); } public XmlNamedElementList Properties { get; set; } } public static class TestClass { public static void Test() { var root = new RootObject { // Characters " <> first" in the first element name are for testing purposes. Properties = new XmlNamedElementList { new Property { id = 1, value = "1", name = "first" }, new Property("property1name", 2, "testvalue"), new Property("property2name", 10, "anothervalue") } }; var xml = root.GetXml(); Debug.WriteLine(xml); } } 

其中生成XML如下:

    <_x0020__x003c__x003e__x0020_first> 1 1   2 testvalue   10 anothervalue    

原始答案

根据要求,这是在List>上实现IXmlSerializable ,其中Key字符串成为集合中的元素名称。

您可能想要做的是调整它以序列化List ,其中:

 public interface IHasElementName { string ElementName { get; set; } } public class Property : IHasElementName { [XmlIgnore] public string name; //could be enum public int id; public string value; #region IHasElementName Members [XmlIgnore] string IHasElementName.ElementName { get { return name; } set { name = value; } } #endregion } 

如果name实际上是Enum,则可以从HasElementName.ElementName返回枚举字符串表示HasElementName.ElementName

该列表如下:

 public class XmlKeyValueList : List>, IXmlSerializable { // TODO: validate that the "Key" string using XmlConvert.VerifyName. // https://msdn.microsoft.com/en-us/library/System.Xml.Serialization.XmlSerializer%28v=vs.110%29.aspx // Any serializer created with the "XmlSerializer(typeof(T), rootAttribute)" must be cached // to avoid resource & memory leaks. class ValueSerializerCache { // By using a nested class with a static constructor, we defer generation of the XmlSerializer until it's actually required. static ValueSerializerCache() { var rootAttribute = new XmlRootAttribute(); rootAttribute.ElementName = ValueTypeName; rootAttribute.Namespace = ValueTypeNamespace; serializer = new XmlSerializer(typeof(T), rootAttribute); } static readonly XmlSerializer serializer; internal static XmlSerializer Serializer { get { return serializer; } } } static string ValueTypeName { get { return typeof(T).DefaultXmlElementName(); } } static string ValueTypeNamespace { get { return typeof(T).DefaultXmlElementNamespace(); } } #region IXmlSerializable Members XmlSchema IXmlSerializable.GetSchema() { return null; } void IXmlSerializable.ReadXml(XmlReader reader) { var typeName = ValueTypeName; reader.ReadStartElement(); // Advance to the first sub element of the list element. while (reader.NodeType == XmlNodeType.Element) { var name = reader.Name; using (var subReader = reader.ReadSubtree()) { var doc = XDocument.Load(subReader); if (doc != null && doc.Root != null) { doc.Root.Name = typeName; using (var docReader = doc.CreateReader()) { var obj = ValueSerializerCache.Serializer.Deserialize(docReader); if (obj != null) { Add(new KeyValuePair(name, (T)obj)); } } } } // Move past the XmlNodeType.Element if (reader.NodeType == XmlNodeType.EndElement) reader.Read(); } } void IXmlSerializable.WriteXml(XmlWriter writer) { foreach (var pair in this) { XDocument doc = new XDocument(); using (var subWriter = doc.CreateWriter()) { // write xml into the writer ValueSerializerCache.Serializer.Serialize(subWriter, pair.Value); } if (doc.Root == null) continue; doc.Root.Name = pair.Key; // Remove redundant namespaces. foreach (var attr in doc.Root.Attributes().ToList()) { if (!attr.IsNamespaceDeclaration || string.IsNullOrEmpty(attr.Value)) continue; if (writer.LookupPrefix(attr.Value) == attr.Name.LocalName) attr.Remove(); } doc.Root.WriteTo(writer); } } #endregion } public static class XmlSerializationHelper { public static string DefaultXmlElementName(this Type type) { var xmlType = type.GetCustomAttribute(); if (xmlType != null && !string.IsNullOrEmpty(xmlType.TypeName)) return xmlType.TypeName; var xmlRoot = type.GetCustomAttribute(); if (xmlRoot != null && !string.IsNullOrEmpty(xmlRoot.ElementName)) return xmlRoot.ElementName; return type.Name; } public static string DefaultXmlElementNamespace(this Type type) { var xmlType = type.GetCustomAttribute(); if (xmlType != null && !string.IsNullOrEmpty(xmlType.Namespace)) return xmlType.Namespace; var xmlRoot = type.GetCustomAttribute(); if (xmlRoot != null && !string.IsNullOrEmpty(xmlRoot.Namespace)) return xmlRoot.Namespace; return string.Empty; } } 

如果UnitItem被更改为

  public class UnitItem { public string AAA; public string BBB; } 

那么XML将是

   testa testb