JAXB 在生成 pojo 时使用元素名称而不是类型

JAXB use element name instead of type when generating pojo

我想使用 jaxb 从 xsd 生成 pojo。 但是 xsd 是由外部供应商提供的,其中元素具有有意义的名称, 但是类型很奇怪。举个例子:

<xs:element name="PersonAddress" type="PerAdr" />

<xs:complexType name="PerAdr">
    <xs:sequence>
        <xs:element name="street" type="xs:string" minOccurs="1" maxOccurs="unbounded" />
        <xs:element name="house" type="xs:string" minOccurs="1" maxOccurs="unbounded" />
    </xs:sequence>
</xs:complexType>

所以生成的class叫做PerAdr。 如何让它生成 classes,其中它们的名称是元素名称,而不是类型,所以在这种情况下它会生成 class PersonAddress.

我有一个巨大的 xsd,所以考虑一个聪明的方法,而不是在 .xjb 文件中写数百行

我不是 JAXB 的专家。但我查看了 JAXB 规范(此处:http://download.oracle.com/otn-pub/jcp/jaxb-2.0-fr-oth-JSpec/jaxb-2_0-fr-spec.pdf)并发现以下内容:


模式派生元素的特征class派生于 “元素声明架构组件”的属性条款 第349页如下:

  • 生成的Java元素class的名称来源于 元素声明 {name} 使用 XML 名称到 Java 标识符 class 个名称的映射算法。

  • 每个生成的元素 class 必须扩展 Java 值 class javax.xml.bind.JAXBElement<T>。下一个项目符号指定 模式派生的 Java class 用于通用参数的名称 T.

  • 如果元素声明的{类型定义}

    • Anonymous:第二个项目符号中的通用参数 T 设置为派生的模式 class 表示按指定生成的匿名类型定义 在第 6.7.3 节中
    • Named: 第二个项目符号中的通用参数 T 设置为 Java class 表示元素声明的 {类型定义}.

因此,人们可能会由此得出结论:一旦您拥有一个具有命名 XSD 类型的 XSD 元素,您就必须处理 Java class 表示该类型并以它命名。这是合乎逻辑的。毕竟,您可能拥有具有相同全局类型的不同 XSD 元素。这是默认映射。

但是,JAXB 允许自定义(XML 模式),您可以使用它覆盖某些内容。比如可以修改XSD类型生成的Javaclass的名称,例如:

<xs:complexType name="USAddress">
  <xs:annotation> <xs:appinfo>
    <jaxb:class name="MyAddress" />
  </xs:appinfo></xs:annotation>
  <xs:sequence>...</xs:sequence>
  <xs:attribute name="country" type="xs:string"/>
</xs:complexType>

因此,结果 Java class 将被命名为 MyAddress,而不是 USAddress。这看起来像是您问题的解决方案,但要利用它,您将需要修改 XSD 中的每个类型定义,这听起来令人生畏,因为您的架构非常庞大。

那么,你能做什么?

首先,您需要确保架构中的每个 XSD 元素及其(全局定义的)类型彼此唯一对应。如果碰巧有几个不同的 XSD 元素具有相同的类型,显然类型名称不能与所有元素都相等。在这种情况下,如果您不喜欢原始类型名称,您只需手动编辑该架构并为这些类型指定更适合您的不同名称。

只有当关系 XSD 元素 <-> 其 XSD 类型是唯一的时,任何自动化才有可能!在这种情况下,您可以从元素名称派生类型名称:使其相同或添加,例如,T 前缀:TPersonAddress.

这通常称为重构,可以自动完成。问题是如何?

嗯,由于 XSD 是 XML,您可以编写一个 XSLT 脚本 来执行必要的转换。但这可能不是那么简单,因为您将不得不稍微分析一下模式。也就是说,识别那里的每个 XSD 元素并找到相应的 XSD 类型,然后更改两个位置的类型名称。或者,您可以在每个 XSD 类型的定义中插入这些自定义指令(<jaxb:...> 元素),如上所述。我不知道编程这样的东西需要多少时间。这肯定会归结为创建索引(使用 <xsl:key> 构造)并对其进行迭代。


或者,我可以向您推荐一些非正统的方法。我们开发了一个名为 FlexDoc/XML 的工具。从本质上讲,它是一个将 XML 文件转换成任何东西的转换器。使用一些类似于 XSLT 的 模板 对转换进行编程。

最初的想法是将类似 XSLT 的方法扩展到通过各种 API 提供的任何类型的基于 Java 的数据源。例如,我们有一个类似的产品叫做 FlexDoc/Javadoc that mimics standard Javadoc. But then we realized that XML itself is also a good field full of various heavy-lifting tasks, for which XSLT is too lightweight. For instance, the generation of easily navigable single documentation by hundreds of XSD and WSDL files, for which we have two template sets now: XSDDoc and WSDLDoc。 (我们也在为 JSON 模式做类似的事情)。

使用 FlexDoc/XML 可以创建一个满足您需要的模板(重命名那些 XSD 类型)。这可以在一个小时内完成,如果您最终购买了 "FlexDoc/XML SDK" 许可证,我们将为您完成。 (人们通常购买 SDK 许可证来自定义 XSDDoc/WSDLDoc 模板。但它同样可以作为单独的工具用于像你的任务。)