【问题标题】:Optimal JAXB XJC code generation and optimal XML schema with inheritance最佳 JAXB XJC 代码生成和最佳 XML 模式与继承
【发布时间】:2012-04-24 22:33:54
【问题描述】:

有很多类似的问题都集中在一个方面进行优化,但每个解决方案都有一个丑陋的缺点。

假设我想开发一个 XML 模式 (XSD),它允许以下文档并希望使用 XJC 生成类:

<Catalogue>
    <Book>...</Book>
    <Journal>...</Journal>
    <Book>...</Book>
    ...
</Catalogue>

架构应该对类型层次结构进行建模(BookJournalPublication 的子类)。当然,这也应该 生成的 Java 类就是这种情况。

我尝试了以下方法,它们都有一个主要问题:

1.) 建模目录以包含所有可能的子类型的xsd:choice

<xsd:complexType name="Catalogue">
    <xsd:choice maxOccurs="unbounded">
        <xsd:element ref="Book" />
        <xsd:element ref="Magazine" />
    </xsd:choice>
</xsd:complexType>

<xsd:element name="Publication" abstract="true" type="Publication" />
<xsd:element name="Book" type="Book"/>
<xsd:element name="Magazine" type="Magazine"/>

<xsd:complexType name="Publication">
    <xsd:sequence></xsd:sequence>
</xsd:complexType>

<xsd:complexType name="Book">
    <xsd:complexContent>
        <xsd:extension base="Publication">
        </xsd:extension>
    </xsd:complexContent>
</xsd:complexType>
...

这里的问题是我必须在choice 元素中提及所有可能的子类型,这在实际应用程序中可能很多。 一个小问题是,尽管Catalogue 属性具有正确的类型List&lt;Publication&gt;,但它的名称很丑bookAndMagazine。 由于冗余架构定义,不是一个选项!

2.) 建模目录以包含父类的xsd:sequence

<xsd:complexType name="Catalogue">
    <xsd:choice maxOccurs="unbounded">
        <xsd:element ref="Publication" maxOccurs="unbounded"/>
    </xsd:choice>
</xsd:complexType>

这只有在 XML 文档的公式类似于 &lt;Publication xsi:type="Book"...&gt; 时才有效。因此,不是一个选择!

3.) 像这里提到的那样使用替代组http://www.xfront.com/ElementHierarchy.html

<xsd:complexType name="Catalogue">
    <xsd:choice maxOccurs="unbounded">
        <xsd:element ref="Publication" maxOccurs="unbounded"/>
    </xsd:choice>
</xsd:complexType>

<xsd:element name="Publication" abstract="true" type="Publication" />
<xsd:element name="Book" type="Book" substitutionGroup="Publication"/>
<xsd:element name="Magazine" type="Magazine" substitutionGroup="Publication"/>

<xsd:complexType name="Publication">
    <xsd:sequence></xsd:sequence>
</xsd:complexType>

<xsd:complexType name="Book">
    <xsd:complexContent>
        <xsd:extension base="Publication">
        </xsd:extension>
    </xsd:complexContent>
</xsd:complexType>
...

这里,代码生成是个问题,因为Catalogue 的内部元素映射到List&lt;JaxbElement&lt;? extends Publication&gt;&gt; 而不是 List&lt;Publication&gt; 。因此,这也不是一个选择。

如何将我的所有目标集中在一起?:

  • 对继承进行建模的规范、非冗余架构(例如在 2.)3.)
  • 从该架构生成的简单且干净的 Java 类,这些类对继承进行建模(如 2.) 和部分1.)
  • 干净的 XML 文档(不像 2.)
  • 使用标准 JAXB,最好不要太多绑定元数据

如果没有与所有这些目标相匹配的解决方案,您更喜欢哪一个?

【问题讨论】:

  • 您能否详细说明为什么选项 3) 不好,以及为什么 List&lt;JaxbElement&lt;? extends Publication&gt;&gt; 不适合您?它实际上很优雅:不仅您有一个 JAXB 对象,而且 JAXBElement 包装器还为您提供了完全限定的元素名称。 xml信息
  • 1.) 我想在其他应用程序部分中使用生成的类层次结构作为一种域模型,我不喜欢让它们依赖于 JaxB 类型。 2) 我正在应用 XJC 插件 jaxb-visitor,它丰富了访问者模式的生成类。 JaxbElement 属性打破了遍历文档树的自然方式。
  • 我也觉得选项 3 很丑。我更喜欢与 pojo 保持接近,并且在这种情况下永远不需要 JAXBElement 提供的东西,因为它都是一个模式。

标签: inheritance xsd jaxb code-generation xjc


【解决方案1】:

我建议使用类似于您的第一个选项的方法,因为我从未见过更清洁的解决方案。

XSD

<xs:element name="Publications" minOccurs="0">
  <xs:complexType>
    <xs:sequence>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element name="Magazine" type="magazine"/>
        <xs:element name="Book" type="book"/>
      </xs:choice>
    </xs:sequence>
  </xs:complexType>
</xs:element>

 <xs:complexType name="magazine">
  <xs:complexContent>
   <xs:extension base="publication">
    <xs:sequence>
      <xs:element name="issueName" type="xs:string" minOccurs="0"/>
    </xs:sequence>
  </xs:extension>
 </xs:complexContent>
</xs:complexType>

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

<xs:complexType name="book">
  <xs:complexContent>
    <xs:extension base="publication">
      <xs:sequence>
        <xs:element name="title" type="xs:string" minOccurs="0"/>
      </xs:sequence>
    </xs:extension>
  </xs:complexContent>
</xs:complexType>

JAVA 这是我用来生成上述 XSD 的 Java 代码。

@XmlElements({
  @XmlElement(name="Magazine", type=Magazine.class),
  @XmlElement(name="Book", type=Book.class)
})
@XmlElementWrapper(name="Publications")
public List<Publication> publications;

【讨论】:

  • 谢谢。我实际上也决定了 1.)。但是,在您的示例中,您正在实现包括一些注释的 Java 类型并从中生成 XSD。我正试图逆转。开发 XSD 并生成代码。有趣的是,生成的 XSD 等于解决方案 1。)
  • 我建议您考虑的一件事是,使用选项 1,您会被这两种子类型所困扰,并且将来必须升级 XSD 以支持新类型。有一些方法可以缓解(为了向前兼容),例如允许未知类型:
【解决方案2】:

如果您可以从代码(而不是 XSD)开始并且可以使用 MOXY,请查看此blog post。它使用没有 JAXBElement 包装器的方法 3。我很想从 XSD 开始做这件事,但我还没有找到。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-10
    • 1970-01-01
    • 1970-01-01
    • 2014-07-04
    • 1970-01-01
    • 1970-01-01
    • 2010-11-28
    • 1970-01-01
    相关资源
    最近更新 更多