从 C# 类代码生成 xsd 注释和文档标签
Posted
技术标签:
【中文标题】从 C# 类代码生成 xsd 注释和文档标签【英文标题】:Generate xsd annotation and documentation tags from C# class code 【发布时间】: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 自动记录。
【问题讨论】:
【参考方案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;
【讨论】:
使用示例:github.com/abcpro-pl/elektronizacja-prawa/blob/master/nes/v2.0/…github.com/abcpro-pl/elektronizacja-prawa/tree/master/nes/v2.0/…以上是关于从 C# 类代码生成 xsd 注释和文档标签的主要内容,如果未能解决你的问题,请参考以下文章