c# – 如何使用注释从类的属性值派生xml元素名称?
发布时间:2020-12-15 20:57:26 所属栏目:百科 来源:网络整理
导读:我有 具有ID和值以及名称的属性.我可以使用XmlElement / XmlArray C#注释代表所有具有单个类的人吗?我想从类属性名称派生xml元素名称; 我的课看起来像: public class Property { public string name; //could be enum public int id; public string value;
我有
具有ID和值以及名称的属性.我可以使用XmlElement / XmlArray C#注释代表所有具有单个类的人吗?我想从类属性名称派生xml元素名称; 我的课看起来像: 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看起来像: <property1name><id>2</id><value>testvalue</value></property1name> <property2name><id>10</id><value>anothervalue</value></property2name> 而不是通常的 <property><name>property1name</name><id>2</id><value>testvalue</value></property> <property><name>property2name</name><id>10</id><value>anothervalue</value></property> 换句话说,xmlelement从类Property的属性名称中获取其名称 解决方法
更新
这是一个快速适应处理您的Property类.首先,列表< T>实现 public interface IHasElementName { string ElementName { get; set; } } public class XmlNamedElementList<T> : List<T>,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<T>(MemberInfo element) where T : Attribute { return (T)GetCustomAttribute(element,typeof(T)); } public static string DefaultXmlElementName(this Type type) { var xmlType = GetCustomAttribute<XmlTypeAttribute>(type); if (xmlType != null && !string.IsNullOrEmpty(xmlType.TypeName)) return xmlType.TypeName; var xmlRoot = GetCustomAttribute<XmlRootAttribute>(type); if (xmlRoot != null && !string.IsNullOrEmpty(xmlRoot.ElementName)) return xmlRoot.ElementName; return type.Name; } public static string DefaultXmlElementNamespace(this Type type) { var xmlType = GetCustomAttribute<XmlTypeAttribute>(type); if (xmlType != null && !string.IsNullOrEmpty(xmlType.Namespace)) return xmlType.Namespace; var xmlRoot = GetCustomAttribute<XmlRootAttribute>(type); if (xmlRoot != null && !string.IsNullOrEmpty(xmlRoot.Namespace)) return xmlRoot.Namespace; return string.Empty; } public static string GetXml<T>(this T obj) { return GetXml(obj,false); } public static string GetXml<T>(this T obj,bool omitNamespace) { return GetXml(obj,new XmlSerializer(obj.GetType()),omitNamespace); } public static string GetXml<T>(this T obj,XmlSerializer serializer) { return GetXml(obj,serializer,false); } public static string GetXml<T>(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,ns); } public static string GetXml<T>(T obj,XmlSerializerNamespaces ns) { return GetXml(obj,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<Property>(); } public XmlNamedElementList<Property> 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<Property> { new Property { id = 1,value = "1",name = "first" },new Property("property1name","testvalue"),new Property("property2name","anothervalue") } }; var xml = root.GetXml(); Debug.WriteLine(xml); } } 其中生成XML如下: <?xml version="1.0" encoding="utf-16"?> <RootObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <Properties> <_x0020__x003C__x003E__x0020_first> <id>1</id> <value>1</value> </_x0020__x003C__x003E__x0020_first> <property1name> <id>2</id> <value>testvalue</value> </property1name> <property2name> <id>10</id> <value>anothervalue</value> </property2name> </Properties> </RootObject> 原始答案 根据要求,这是List< KeyValuePair< string,T>>上IXmlSerializable的实现.其中Key字符串成为集合中的元素名称. 您可能想要做的是调整它以序列化List< IHasElementName>哪里: 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 } 如果名称实际上是Enum,则可以从HasElementName.ElementName返回枚举字符串表示形式. 该列表如下: public class XmlKeyValueList<T> : List<KeyValuePair<string,T>>,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); } 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<string,T>(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<XmlTypeAttribute>(); if (xmlType != null && !string.IsNullOrEmpty(xmlType.TypeName)) return xmlType.TypeName; var xmlRoot = type.GetCustomAttribute<XmlRootAttribute>(); if (xmlRoot != null && !string.IsNullOrEmpty(xmlRoot.ElementName)) return xmlRoot.ElementName; return type.Name; } public static string DefaultXmlElementNamespace(this Type type) { var xmlType = type.GetCustomAttribute<XmlTypeAttribute>(); if (xmlType != null && !string.IsNullOrEmpty(xmlType.Namespace)) return xmlType.Namespace; var xmlRoot = type.GetCustomAttribute<XmlRootAttribute>(); if (xmlRoot != null && !string.IsNullOrEmpty(xmlRoot.Namespace)) return xmlRoot.Namespace; return string.Empty; } } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |