java 使用导入的 XSD 和绑定生成 JAXB 类

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29763259/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 15:53:38  来源:igfitidea点击:

JAXB class generation with imported XSD and binding

javaxmlbindingxsdjaxb

提问by user3057702

I am trying to generate classes from following common.xsdwhich imports x.xsdand y.xsd.

我正在尝试从以下common.xsd导入x.xsdy.xsd.

common.xsdis as follows:

common.xsd如下:

<?xml version="1.0"?>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:import namespace="mynamespace:x" schemaLocation="x.xsd"/>
    <xs:import namespace="mynamespace:y" schemaLocation="y.xsd"/>
</xs:schema>

I try to use a binding file that specifies a common interface that is to be implemented by the generated classes. My binding file is as follows:

我尝试使用一个绑定文件,该文件指定要由生成的类实现的公共接口。我的绑定文件如下:

jaxb:extensionBindingPrefixes="inheritance" version="2.1">

<jaxb:globalBindings> 
    <jaxb:javaType name="java.lang.Long" xmlType="xsd:integer"/> 
</jaxb:globalBindings>

<jaxb:bindings schemaLocation="common.xsd" node="/xsd:schema">

    <jaxb:bindings node="xsd:complexType[@name='Customer']">
        <inheritance:implements>jaxb.BaseMessage</inheritance:implements>
        <jaxb:class />
    </jaxb:bindings>

    <jaxb:bindings node="xsd:complexType[@name='Payments']">
        <inheritance:implements>jaxb.BaseMessage</inheritance:implements>
        <jaxb:class />
    </jaxb:bindings>

I tried to generate the code but it complains that:

我试图生成代码,但它抱怨:

[ERROR] XPath evaluation of "xsd:complexType[@name='Customer']" results in empty target node
[ERROR] XPath evaluation of "xsd:complexType[@name='Payments']" results in empty target node

How can I define the nodes in the bindings files are actually in the individual external XSD files but not in common.xsd?

如何定义绑定文件中的节点实际上在单个外部 XSD 文件中而不是在common.xsd.

回答by vallismortis

Normally, the way you would want to do this would be to use Schema Component Designators (SCD)instead of XPath.

通常,您希望这样做的方法是使用架构组件指示符 (SCD)而不是 XPath。

Using SCD for customizations

使用 SCD 进行自定义

[XPath] is also error prone, because it relies on the way schema documents are laid out, because the schemaLocation attribute needs to point to the right schema document file. When a schema is split into multiple files for modularity (happens especially often with large schemas), then you'd have to find which schema file it is. Even though you can use relative paths, this hard-coding of path information makes it hard to pass around the binding file to other people.

[XPath] 也容易出错,因为它依赖于架构文档的布局方式,因为 schemaLocation 属性需要指向正确的架构文档文件。当模式被拆分为多个文件以实现模块化时(尤其经常发生在大型模式中),那么您必须找到它是哪个模式文件。尽管您可以使用相对路径,但这种对路径信息的硬编码使得很难将绑定文件传递给其他人。

SCD Support

SCD 支持

Compared to the standard XPath based approach, SCD allows more robust and concise way of identifying a target of a customization. For more about SCD, refer to the scd example. Note that SCD is a W3C working draft, and may change in the future.

与基于 XPath 的标准方法相比,SCD 允许以更健壮和简洁的方式识别定制目标。有关 SCD 的更多信息,请参阅 scd 示例。请注意,SCD 是 W3C 工作草案,将来可能会更改。

Unfortunately, due to a bug in XJC, SCD does not work in combination with vendor extensions. You would see an error like:

不幸的是,由于XJC 中的一个错误,SCD 不能与供应商扩展结合使用。您会看到如下错误:

[ERROR] cvc-elt.1: Cannot find the declaration of element 'inheritance:implements'.

The author of jaxb2-basicshas recently written up a detailed explanationof that particular problem. Basically, if you want to use vendor extensions, you are stuck with XPath (and its limitations) for now.

作者jaxb2-basics最近撰写了对该特定问题的详细解释。基本上,如果您想使用供应商扩展,您现在只能使用 XPath(及其限制)。

An XPath-based solution

基于 XPath 的解决方案

Here is a complete, working example using XPath with the vendor extensions based on the information you provided in your question. I believe the proper way to generate the classes from the imported schemas are via a separate bindings element. As proof that this is working as expected, the class generated from this binding (Cust) is visible and reused by those classes generated by common.xsd. Each generated class implements the base class jaxb.BaseMessage.

这是一个完整的工作示例,根据您在问题中提供的信息,使用 XPath 和供应商扩展。我相信从导入的模式生成类的正确方法是通过单独的绑定元素。作为这按预期工作的证明,从此绑定 ( Cust)生成的类是可见的,并且由 生成的那些类可以重用common.xsd。每个生成的类都实现基类jaxb.BaseMessage

I believe this is as good a solution as you will find until the XJC bug is fixed.

我相信这是一个很好的解决方案,直到 XJC 错误得到修复。

src/main/resources/bindings.xjb:

src/main/resources/bindings.xjb

<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    jaxb:version="2.1"
    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
    xmlns:inheritance="http://jaxb2-commons.dev.java.net/basic/inheritance"
    jaxb:extensionBindingPrefixes="xjc inheritance">

  <jaxb:globalBindings>
    <jaxb:javaType name="java.lang.Long" xmlType="xsd:integer" />
  </jaxb:globalBindings>

  <jaxb:bindings schemaLocation="schema/x.xsd">
    <jaxb:bindings node="//xsd:complexType[@name='Customer']">
      <jaxb:class name="Cust" />
      <inheritance:implements>jaxb.BaseMessage</inheritance:implements>
    </jaxb:bindings>
  </jaxb:bindings>

  <jaxb:bindings schemaLocation="schema/y.xsd">
    <jaxb:bindings node="//xsd:complexType[@name='Payments']">
      <jaxb:class />
      <inheritance:implements>jaxb.BaseMessage</inheritance:implements>
    </jaxb:bindings>
  </jaxb:bindings>

  <jaxb:bindings schemaLocation="schema/common.xsd">
    <jaxb:bindings node="//xsd:complexType[@name='CustomerPayments']">
      <jaxb:class />
      <inheritance:implements>jaxb.BaseMessage</inheritance:implements>
    </jaxb:bindings>
  </jaxb:bindings>

</jaxb:bindings>

src/main/resources/schema/common.xsd:

src/main/resources/schema/common.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema version="1.0"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:x="http://test.org/common/x"
    xmlns:y="http://test.org/common/y"
    targetNamespace="http://test.org/common">

  <xsd:import namespace="http://test.org/common/x" schemaLocation="x.xsd" />
  <xsd:import namespace="http://test.org/common/y" schemaLocation="y.xsd" />

  <xsd:complexType name="CustomerPayments">
    <xsd:sequence>
      <xsd:element name="customer" type="x:Customer" />
      <xsd:element name="payments" type="y:Payments" />
    </xsd:sequence>
  </xsd:complexType>

</xsd:schema>

src/main/resources/schema/x.xsd:

src/main/resources/schema/x.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema version="1.0"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    elementFormDefault="qualified"
    attributeFormDefault="unqualified"
    targetNamespace="http://test.org/common/x">

  <xsd:complexType name="Customer">
    <xsd:sequence>
      <xsd:element name="name" type="xsd:string" />
    </xsd:sequence>
  </xsd:complexType>

</xsd:schema>

src/main/resources/schema/y.xsd:

src/main/resources/schema/y.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema version="1.0"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    elementFormDefault="qualified"
    attributeFormDefault="unqualified"
    targetNamespace="http://test.org/common/y">

  <xsd:complexType name="Payments">
    <xsd:sequence>
      <xsd:element name="amount" type="xsd:float" />
    </xsd:sequence>
  </xsd:complexType>

</xsd:schema>

build.xml:

build.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE project>
<project name="JAXB XPath Test" default="xjc" basedir=".">

  <property name="build.folder" location="build" />

  <taskdef name="xjc" classname="org.jvnet.jaxb2_commons.xjc.XJC2Task">
    <classpath>
        <fileset dir="${basedir}/lib">
          <include name="jaxb-impl-2.2.6.jar" />
          <include name="jaxb-xjc-2.2.6.jar" />
          <include name="jaxb2-basics-ant-0.9.4.jar" />
          <include name="javaparser-1.0.11.jar" />
          <include name="commons-lang3-3.2.jar" />
        </fileset>
    </classpath>
  </taskdef>

  <target name="xjc" description="Generate the source code.">

    <xjc destdir="${basedir}/src/main/java" extension="true">

      <arg line="
        -Xequals
        -XhashCode
        -XtoString
        -Xcopyable
        -Xmergeable
        -Xinheritance" />

      <binding dir="${basedir}/src/main/resources">
        <include name="**/*.xjb" />
      </binding>

      <schema dir="${basedir}/src/main/resources/schema">
        <include name="**/*.xsd" />
      </schema>

      <classpath>
        <fileset dir="${basedir}/lib">
            <include name="jaxb2-basics-0.9.4.jar"/>
            <include name="jaxb2-basics-runtime-0.9.4.jar"/>
            <include name="jaxb2-basics-tools-0.9.4.jar"/>
            <include name="commons-beanutils-1.8.0.jar"/>
            <include name="commons-lang3-3.2.jar"/>
            <include name="commons-logging-1.1.1.jar"/>
        </fileset>
      </classpath>

    </xjc>

  </target>

</project>

回答by vallismortis

I'm posting a second answer because I believe what you are trying to achieve is possible without vendor extensions, but I also think that my original answer may be useful to others who need vendor extensions.

我发布了第二个答案,因为我相信您可以在没有供应商扩展的情况下实现目标,但我也认为我的原始答案可能对需要供应商扩展的其他人有用。

This example also removes the namespaces, but they could be added back easily. The same build script is used for this answer as in my previous one.

此示例还删除了命名空间,但可以轻松地将它们添加回来。与我之前的答案相同,此答案使用了相同的构建脚本。

src/main/resources/bindings.xjb:

src/main/resources/bindings.xjb

<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    jaxb:version="2.1"
    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
    jaxb:extensionBindingPrefixes="xjc"
    xmlns:common="schema/common.xsd">

  <jaxb:globalBindings>
    <jaxb:javaType name="java.lang.Long" xmlType="xsd:integer" />
    <xjc:superInterface name="jaxb.BaseMessage" />
  </jaxb:globalBindings>

</jaxb:bindings>

src/main/resources/schema/common.xsd:

src/main/resources/schema/common.xsd

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

  <xsd:include schemaLocation="x.xsd" />
  <xsd:include schemaLocation="y.xsd" />

  <xsd:complexType name="CustomerPayments">
    <xsd:sequence>
      <xsd:element name="customer" type="Customer" />
      <xsd:element name="payments" type="Payments" />
    </xsd:sequence>
  </xsd:complexType>

</xsd:schema>

src/main/resources/schema/x.xsd:

src/main/resources/schema/x.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema version="1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsd:complexType name="Customer">
      <xsd:sequence>
        <xsd:element name="name" type="xsd:string" />
      </xsd:sequence>
    </xsd:complexType>
</xsd:schema>

src/main/resources/y.xsd:

src/main/resources/y.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema version="1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsd:complexType name="Payments">
      <xsd:sequence>
        <xsd:element name="amount" type="xsd:float" />
      </xsd:sequence>
    </xsd:complexType>
</xsd:schema>

回答by lexicore

Why don't you just point your schemaLocationto x.xsdand y.xsd, where the types are defined?

为什么你不干脆点你schemaLocationx.xsdy.xsd,其中被定义的类型?

<jaxb:bindings schemaLocation="x.xsd" node="/xsd:schema">
    <jaxb:bindings node="xsd:complexType[@name='Customer']">
        <inheritance:implements>jaxb.BaseMessage</inheritance:implements>
        <jaxb:class />
    </jaxb:bindings>
</jaxb:bindings>

<jaxb:bindings schemaLocation="y.xsd" node="/xsd:schema">
    <jaxb:bindings node="xsd:complexType[@name='Payments']">
        <inheritance:implements>jaxb.BaseMessage</inheritance:implements>
        <jaxb:class />
    </jaxb:bindings>
</jaxb:bindings>

回答by Code_Eraser

I think it doesn't work because you didn't start the node with //

我认为它不起作用,因为您没有以 // 启动节点

Try this:

试试这个:

<jaxb:bindings node="//xsd:complexType[@name='Customer']">
    <inheritance:implements>jaxb.BaseMessage</inheritance:implements>
</jaxb:bindings>