【问题标题】:Generate xsd annotation and documentation tags from C# class code从 C# 类代码生成 xsd 注释和文档标签
【发布时间】:2017-08-29 02:02:43
【问题描述】:

使用 xds.exe(或 other methods)从类生成 XSD 文件效果很好,但我找不到将文档(或任何类型的描述)插入输出 XSD 的方法。

例如C#类

public class Animal
{
    public int NumberOfLegs;
}

生成 XSD

<?xml version="1.0" encoding="utf-16"?>
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Animal" nillable="true" type="Animal" />
  <xs:complexType name="Animal">
    <xs:sequence>
      <xs:element minOccurs="1" maxOccurs="1" name="NumberOfLegs" type="xs:int" />
    </xs:sequence>
  </xs:complexType>
</xs:schema>

不过,我希望能够将 XSD 注释作为元数据添加到类中,以便 XSD 出现

<xs:complexType name="Animal">
  <xs:sequence>
    <xs:element minOccurs="1" maxOccurs="1" name="NumberOfLegs" type="xs:int">
      <xs:annotation>
        <xs:documentation>Will need to be greater than 0 to walk!</xs:documentation>
      </xs:annotation>
    </xs:element>
  </xs:sequence>
</xs:complexType>

是否有任何简洁的方法可以在 C# 代码中实现这一点?向 xml 元素/属性添加任何类型的描述的任何方式都可以。注释必须与实际代码类似:

public class Animal
{
    [XmlAnnotation("Will need to be greater than 0 to walk!")]
    public int NumberOfLegs;
}

也就是说,它需要从 cmets 自动记录。

【问题讨论】:

    标签: c# xml xsd


    【解决方案1】:

    尝试以下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Data;
    using System.Xml;
    using System.Xml.Linq;
    using System.IO;
    
    
    namespace ConsoleApplication49
    {
    
        class Program
        {
            const string FILENAME = @"c:\temp\test.xml";
            static void Main(string[] args)
            {
                StreamReader reader = new StreamReader(FILENAME);
                reader.ReadLine(); //skip the xml identification with utf-16 encoding
                XDocument doc = XDocument.Load(reader);
    
                XElement firstNode = (XElement)doc.FirstNode;
                XNamespace nsXs = firstNode.GetNamespaceOfPrefix("xs");
    
                XElement sequence = doc.Descendants(nsXs + "element").FirstOrDefault();
    
                sequence.Add(new XElement(nsXs + "annotation",
                    new XElement(nsXs + "documention", "Will need to be greater than 0 to walk!")
                    ));
    
            }
        }
    
    
    }
    

    【讨论】:

    • 抱歉,我的问题可能不够具体。 cmets 需要与实际代码并列,我将更新问题。
    【解决方案2】:

    这是一个非常丑陋的解决方案,但它适用于我的项目。

      public virtual XElement GetSchema() {
            var schemas = new XmlSchemas();
            var exporter = new XmlSchemaExporter(schemas);
            var importer = new XmlReflectionImporter();
            var mapping = importer.ImportTypeMapping(this.GetType());
            exporter.ExportTypeMapping(mapping);
    
            using (var schemaWriter = new StringWriter()) {
                foreach (System.Xml.Schema.XmlSchema schema in schemas) {
                    schema.Write(schemaWriter);
                }
    
                var xsdText = schemaWriter.ToString();
                var xsd = XElement.Parse(xsdText);
                using (var controller = new XsdAnnotationController()) {
                  xsd = controller.AddAnnotations(xsd);
                }
    
                return xsd;
            }
        }
    

    注解属性

    [AttributeUsage(AttributeTargets.Class)]
    public class XmlAnnotationAttribute : Attribute {
        public string Annotation { get; set; }
        public XmlAnnotationAttribute() { }
        public XmlAnnotationAttribute(string annotation) : this() {
            Annotation = annotation;
        }
    }
    

    注解控制器

    public class XsdAnnotationController : IDisposable {
        List<Type> Types = null;
        public XsdAnnotationController() {
            var asm = System.Reflection.Assembly.GetCallingAssembly();
            Type[] allTypes = null;
            try {
                allTypes = asm.GetTypes();
            }
            catch (Reflection.ReflectionTypeLoadException ex) {
                allTypes = ex.Types;
            }
            if (allTypes != null) {
                Types = allTypes.Where(t => t.IsClass).ToList();
            }
        }
        public XElement AddAnnotations(XElement xsd) {
            if (xsd != null && xsd.HasElements) {
    
                // Add annotations for classes
                var xsdTypes = xsd.Elements().Where(x => (x.Name.LocalName == "complexType" || x.Name.LocalName == "simpleType") && x.Attribute("name") != null && x.Attribute("name").Value != null);
                foreach (var xsdType in xsdTypes) {
                    var typeName = xsdType.Attribute("name").Value;
                    var type = GetClassType(typeName);
                    var annotation = GetTypeAnnotation(type);
                    if (annotation != null && xsdType.Elements().Where(x => x.Name.LocalName == "annotation").Count() == 0) {
                        xsdType.AddFirst(new XElement(XName.Get("annotation", xsdType.Name.NamespaceName),
                            new XElement(XName.Get("documentation", xsdType.Name.NamespaceName),
                                new XText(annotation)
                            )
                        ));
    
                        var elements = xsd.Descendants().Where(x => x.Attribute("type") != null && (x.Attribute("type").Value == typeName || x.Attribute("type").Value.EndsWith($":{typeName}")));
                        foreach (var element in elements) {
                            if (element.Elements().Where(x => x.Name.LocalName == "annotation").Count() == 0) {
                                element.AddFirst(new XElement(XName.Get("annotation", element.Name.NamespaceName),
                                    new XElement(XName.Get("documentation", element.Name.NamespaceName),
                                        new XText(annotation)
                                    )
                                ));
                            }
                        }
                    }
    
                    // Add annotations for properties
                    if (type != null) {
                        var xsdElements = xsdType.Descendants().Where(x => x.Name.LocalName == "element" && x.Attribute("name") != null);
                        var properties = type.GetProperties();
                        foreach (var property in properties) {
                            var propertyName = GetPropertyXmlName(property);
                            var propertyAnnotation = GetPropertyAnnotation(property);
                            if (propertyAnnotation != null) {
                                var xsdElement = xsdElements.Where(x => x.Attribute("name").Value == propertyName).FirstOrDefault();
                                if (xsdElement.IsNotNull()) {
                                    if (xsdElement.Elements().Where(x => x.Name.LocalName == "annotation").Count() == 0) {
                                        xsdElement.AddFirst(new XElement(XName.Get("annotation", xsdElement.Name.NamespaceName),
                                            new XElement(XName.Get("documentation", xsdElement.Name.NamespaceName),
                                                new XText(propertyAnnotation)
                                            )
                                        ));
                                    }
                                }
                            }
                        }
                    }
    
                }
    
            }
            return xsd;
        }
    
        public void Dispose() { }
    
        private Type GetClassType(string xsdTypeName) {
            if (Types != null && xsdTypeName != null) {
                foreach (var type in Types) {
                    var xmlTypeName = GetXmlTypeName(type);
                    if (xmlTypeName != null && xmlTypeName.Equals(xsdTypeName)) {
                        return type;
                    }
                }
            }
            return default;
        }
    
        private string GetTypeAnnotation(Type type) {
            if (type != null) {
                XmlAnnotationAttribute[] attributes = (XmlAnnotationAttribute[])type.GetCustomAttributes(typeof(XmlAnnotationAttribute), false);
                if (attributes != null && attributes.Length > 0) {
                    return attributes[0].Annotation;
                }
            }
            return default;
        }
    
        private string GetPropertyAnnotation(Reflection.PropertyInfo property) {
            if (property != null) {
                XmlAnnotationAttribute[] attributes = (XmlAnnotationAttribute[])property.GetCustomAttributes(typeof(XmlAnnotationAttribute), false);
                if (attributes != null && attributes.Length > 0) {
                    return attributes[0].Annotation;
                }
            }
            return default;
        }
    
        private string GetPropertyXmlName(Reflection.PropertyInfo property) {
            if (property.IsNotNull()) {
                XmlElementAttribute[] attributes = (XmlElementAttribute[])property.GetCustomAttributes(typeof(XmlElementAttribute), false);
                if (attributes != null && attributes.Length > 0) {
                    return attributes[0].ElementName;
                }
                else {
                    XmlAttributeAttribute[] attributes2 = (XmlAttributeAttribute[])property.GetCustomAttributes(typeof(XmlAttributeAttribute), false);
                    if (attributes2 != null && attributes2.Length > 0) {
                        return attributes2[0].AttributeName;
                    }
                }
    
                return property.Name;
            }
            return default;
        }
    
        public string GetXmlTypeName(Type type) {
            if (type.IsNotNull()) {
                XmlTypeAttribute[] attributes = (XmlTypeAttribute[])type.GetCustomAttributes(typeof(XmlTypeAttribute), false);
                if (attributes != null && attributes.Length > 0) {
                    return attributes[0].TypeName;
                }
                else {
                    return type.Name;
                }
            }
            return default;
        }
    }
    

    现在你可以描述类了

    // [XmlType("Animal")]
    [XmlAnnotation("Animal class annotation")]
    public class Animal { 
      [XmlAnnotation("Will need to be greater than 0 to walk!")] 
      public int NumberOfLegs { get; set; }
    }
    
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-30
    • 2011-01-03
    相关资源
    最近更新 更多