【问题标题】:schemagen: How to share classes, but not their namespaces?schemagen:如何共享类,而不是它们的命名空间?
【发布时间】:2013-09-22 10:48:21
【问题描述】:

我有两个顶级课程,它们按组成共享第三个课程。示例:

@XmlRootElement
@XmlType(namespace = "http://example.com/foo")
public class Foo {
    public Shared shared;
}

@XmlRootElement
@XmlType(namespace = "http://example.com/bar")
public class Bar {
    public Shared shared;
}

public class Shared {
    public String string;
}

这些类中的每一个都分配给不同编译单元(模块)中的不同包。 现在,当我在每个顶级类上使用 schemagen 时,我希望 Shared 类具有与顶级类相同的名称空间。所以 Foo 的输出应该是这样的:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="foo" type="Foo"/>

  <xs:complexType name="Foo">
    <xs:sequence>
      <xs:element name="shared" type="Shared" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="Shared">
    <xs:sequence>
      <xs:element name="string" type="xs:string" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>
</xs:schema>

但是,它不是这样工作的。相反,Shared 类具有默认命名空间,因此我得到了两个模式文件,一个用于 Foo 的命名空间,一个用于 Shared 的命名空间。

有没有办法解决这个问题,而无需明显的解决方案来复制 Shared 类,从而不再共享它?

【问题讨论】:

    标签: java schemagen


    【解决方案1】:

    如果共享类应该与顶级类具有相同的名称空间,则必须复制它。如果真的要共享,必须在第三个 XSD 中定义,并导入到两个顶级 XSD 中。所以 Foo 的结果应该是这样的:

    <?xml version="1.0" encoding="UTF-8"?>
    <xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:tns="http://www.example.org/schema/foo"
        xmlns:shared="http://www.example.org/schema/shared"
        targetNamespace="http://www.example.org/schema/foo">
    
        <xs:import namespace="http://www.example.org/schema/shared" schemaLocation="http://www.example.org/schema/shared/shared.xsd"/>
    
        <xs:element name="foo" type="Foo"/>
    
        <xs:complexType name="Foo">
            <xs:sequence>
                <xs:element name="shared" type="shared:Shared" minOccurs="0"/>
            </xs:sequence>
        </xs:complexType>
    
    </xs:schema>
    

    然后可以将 Shared 的 XSD 导入两个顶级 XSD。如果您的 Shared XSD 位于单独的项目中,您可能需要一个目录文件来指定其位置:

    PUBLIC "http://www.example.org/schema/shared" "../../../../shared/src/main/xsd/shared.xsd"
    

    我总是使用契约优先,即创建 XSD 并让 JAXB 生成类。您正在使用 schemagen 基于类生成 XSD。以防万一您使用的是jaxb2-maven-plugin,我找到了Parameter transformSchemas,这听起来像是在做您需要的事情。它允许您指定架构映射并将xs:import 语句写入生成的XSD。没试过,希望对你有帮助。

    【讨论】:

    • 感谢您的详细说明。顺便说一句:是的,我正在使用 jaxb2-maven-plugin。但是,transformSchema 指令仅控制命名空间前缀,不控制输出模式 - 请参阅我的答案。
    【解决方案2】:

    在调查问题并详细说明选项后,我决定更改设计并为我的所有类使用一个且只有一个命名空间。理由如下:

    1. 类和命名空间之间的关系自然是一对一的。即使我手动模拟 XSD 以便我的实例文档正确验证,JAXB 解组器也会忽略属于不匹配的名称空间的元素,因此破解 XSD 根本没有帮助。

    2. 我可以轻松地在多个包和编译单元上重用相同的命名空间。只需要正确设置类路径,当使用 jaxb2-maven-plugin 时,Maven 将为我做这件事。

    3. 我可以轻松地将我的所有类与一个命名空间相关联,并且每个顶级元素仍然具有不同的 XSD 文件。优点是每个输出 XSD 文件仅包含在运行 schemagen 时从包含的根元素类引用的类(即复杂类型)。

    进行此更改后,我会在每个编译单元中获得一个 XSD 文件。每个编译单元只包含一个根元素(即类)。每个根元素仅引用通过表示根元素的类可强访问的复杂类型。这正是我想要的。

    【讨论】:

    • 感谢您发布您的解决方案!
    猜你喜欢
    • 2019-01-27
    • 1970-01-01
    • 2021-11-21
    • 1970-01-01
    • 2018-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多