使用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;
}
也就是说,需要从评论中自动记录。
答案 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; }
}