这是一个非常丑陋的解决方案,但它在我的项目中起作用。
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) {
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)
)
));
}
}
}
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;
}
}
现在你可以描述这个类了。
[XmlAnnotation("Animal class annotation")]
public class Animal {
[XmlAnnotation("Will need to be greater than 0 to walk!")]
public int NumberOfLegs { get; set; }
}