从C#类代码生成xsd注释和文档标记

时间:2017-04-04 03:11:21

标签: c# xml xsd

使用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;
}

也就是说,需要从评论中自动记录。

2 个答案:

答案 0 :(得分:0)

请尝试以下操作:

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!")
                ));

        }
    }


}

答案 1 :(得分:0)

这是一个非常丑陋的解决方案,但它在我的项目中有效。

  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; }
}