使用代码生成

时间:2016-07-25 06:11:39

标签: c# .net xsd code-generation

我正在使用CodeDOM从几个xsd文件构建代码。因此,假设我们有一些映射,从xsd中定义的名称空间到已经创建的程序集中的名称空间:

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:abw="MyNamespace" xmlns:bfm="BaseNamespace" 
        xmlns:gml="http://www.opengis.net/gml/3.2" elementFormDefault="qualified" targetNamespace="MyNamespace" 
        version="1.0.1.0">
  <import namespace="BaseNamespace" schemaLocation="Base.xsd"/>
  <import namespace="http://www.opengis.net/gml/3.2" schemaLocation="http://schemas.opengis.net/gml/3.2.1/gml.xsd"/>

  <element name="MyClass" substitutionGroup="bfm:MyBaseClass" type="abw:MyClassType"/>
  <complexType name="MyClassType">
    <complexContent>
      <extension base="bfm:MyBaseClassType">
        <sequence>
          <element maxOccurs="unbounded" minOccurs="0" name="Property1" type="gml:ReferenceType">
            <annotation>
              <appinfo>
                <targetElement xmlns="http://www.opengis.net/gml/3.2">abw:MyClass2</targetElement>
                <reversePropertyName xmlns="http://www.opengis.net/gml/3.2">abw:MyClassAlias</reversePropertyName>
              </appinfo>
            </annotation>
          </element>
        </sequence>
      </extension>
    </complexContent>
  </complexType>
</schema>

现在 - 由于命名空间BaseNamespacegml的程序集已经存在 - 我只想构建MyClass的源代码,它应该自动引用基类{{ 1}}和bfm:MyBaseClass添加gml:ReferenceType - 指令。

所以我为using创建了CodeNamespace,它从xsd应用了名称空间targetNamespace。现在我循环MyNamespace中的类型并过滤我的xsd中存在的类型,因为所引用的xsd文件中的所有其他类型已经已经分配给它们的程序集。如果我的xsd中未定义类型,则应将 not 添加到代码中,但应添加CodeNamespace

using

medthod var codeNamepscace = new CodeNamespace("targetNamepscae"); var tmp = code.Types.Cast<CodeTypeDeclaration>().ToArray(); foreach (var type in tmp) { var typeFromSchema = schema.SchemaTypes.Names.Cast<XmlQualifiedName>().FirstOrDefault(x => x.Name == type.Name); if (typeFromSchema == null) { string xsdNamespace = ???; // how to get the xsd-namespace for the current type here? Console.WriteLine(String.Format("Found referenced type {0} which is not declared in current schema", type.Name)); // omit the type from the current namespace and add a using-directive to the generated source-file if not yet done code.Types.Remove(type); // add a using-directive for the type if not already done if (!((IList)code.Imports).Contains(typeFromSchema.Namespace)) code.Imports.Add(new CodeNamespaceImport(GetDotNetNSFromXsdNS(xsdNamespace))); } } 定义了从xsd-files中定义的名称空间到程序集内的名称空间的映射。

我现在的问题是:我如何从xsd中为GetDotNetNSFromXsdNS中的类型获取命名空间?特别是:如何从生成中排除CodeNamepspacegml:ReferenceType并通过bfm:MyBaseClass添加它们?

1 个答案:

答案 0 :(得分:0)

以下解决方案适合我 - 虽然我认为它更像是一种解决方法:

var tmp = code.Types.Cast<CodeTypeDeclaration>().ToArray();     // temp. copy of our types-list to avoid ModifiedException during iteration
foreach (var type in tmp)
{
    var attributes = type.CustomAttributes.Cast<CodeAttributeDeclaration>().Where(x => x.Name.StartsWith("System.Xml.Serialization"));
    var namespaceAttribute = attributes.SelectMany(x => x.Arguments.Cast<CodeAttributeArgument>()).FirstOrDefault(x => x.Name == "Namespace");
    string xsdNamespace = ((CodePrimitiveExpression)namespaceAttribute.Value).Value as string;
    if (xsdNamespace != schema.TargetNamespace)
    {
        Console.WriteLine("INFO: Found referenced type {0} which is not declared in current schema", type.Name);

        // omit the type from the current namespace and add a using-directive to the generated source-file if not yet done
        code.Types.Remove(type);

        var nameWithinAssembly = this.m_typeMapper.GetDotNetNamespaceFromXsdNamespace(xsdNamespace);
        // add a using-directive for the type if not already done
        if (!(code.Imports.Cast<CodeNamespaceImport>().Any(x => x.Namespace == nameWithinAssembly))) code.Imports.Add(new CodeNamespaceImport(nameWithinAssembly));
    }
}

这里我们假设来自xsd的命名空间在序列化属性中被镜像。因此,我们为ozur CustomAttributes中的每个类型获取CodeNameapace,并检查它是否具有Namespace - 来自System.Xml.Serialization的任何属性的using属性。最后,我们要做的就是检查用于序列化的命名空间是否等于schemas target-namespace。如果这个条件没有通过,那么应该使用timeout - 指令推断出类型,该指令是用最后一行完成的。