【问题标题】:Codegeneration with usings使用 usings 生成代码
【发布时间】:2016-11-28 09:14:17
【问题描述】:

我正在使用 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 的源代码,它应该自动引用基类 bfm:MyBaseClassgml:ReferenceType添加using-directive。

所以我为targetNamespace 创建了一个CodeNamespace,它应用来自xsd 的命名空间MyNamespace。现在我循环该CodeNamespace 中的类型并过滤那些存在于我的xsd 中的类型,因为引用的xsd 文件中的所有其他类型已经具有 分配给它们的程序集。如果一个类型没有在我的 xsd 中定义,它应该添加到代码中,但是应该添加一个using

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

方法GetDotNetNSFromXsdNS 定义了从xsd 文件中定义的命名空间到程序集中的命名空间的映射。

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

【问题讨论】:

    标签: c# .net xsd code-generation


    【解决方案1】:

    以下解决方案对我有用 - 尽管我认为它更像是一种解决方法:

    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 CodeNameapace 中的每种类型获取 CustomAttributes,并检查它是否在其来自 System.Xml.Serialization 的任何属性上定义了 Namespace-property。最后,我们要做的就是检查这个用于序列化的命名空间是否等于模式目标命名空间。如果此条件未通过,则应使用 using-directive 推断类型,该指令在最后一行完成。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-03
      • 1970-01-01
      • 1970-01-01
      • 2011-12-07
      • 1970-01-01
      • 2016-06-12
      • 1970-01-01
      相关资源
      最近更新 更多