web-dev-qa-db-ja.com

インポートされたXSDとバインディングを使用したJAXBクラスの生成

common.xsdx.xsdをインポートする次のy.xsdからクラスを生成しようとしています。

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>

生成されたクラスによって実装される共通のインターフェースを指定するバインディングファイルを使用しようとしています。私のバインディングファイルは次のとおりです。

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>

コードを生成しようとしましたが、次のように文句を言います。

[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

バインディングファイルのノードが実際には個々の外部XSDファイルにあるが、common.xsdにはないことを定義するにはどうすればよいですか?

11
user3057702

通常、これを実行する方法は、XPathの代わりに Schema Component Designators(SCD) を使用することです。

カスタマイズにSCDを使用

[XPath]は、schemaLocation属性が適切なスキーマドキュメントファイルを指す必要があるため、スキーマドキュメントのレイアウト方法に依存しているため、エラーが発生しやすくなります。モジュール化のためにスキーマが複数のファイルに分割されている場合(特に大きなスキーマでよく発生します)、それがどのスキーマファイルであるかを見つける必要があります。相対パスを使用することはできますが、このパス情報のハードコーディングにより、バインディングファイルを他の人に渡すことが困難になります。

SCDサポート

標準のXPathベースのアプローチと比較して、SCDは、カスタマイズのターゲットを識別するためのより堅牢で簡潔な方法を可能にします。 SCDの詳細については、scdの例を参照してください。 SCDはW3Cワーキングドラフトであり、将来変更される可能性があることに注意してください。

残念ながら、 XJCのバグ のため、SCDはベンダー拡張機能と組み合わせて機能しません。次のようなエラーが表示されます。

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

jaxb2-basics の作者は最近その特定の問題の 詳細な説明 を書きました。基本的に、ベンダー拡張機能を使用したい場合は、今のところXPath(およびその制限)に固執しています。

XPathベースのソリューション

これは、質問で提供した情報に基づいて、ベンダー拡張機能を備えたXPathを使用した完全な実例です。インポートされたスキーマからクラスを生成する適切な方法は、個別のバインディング要素を使用することだと思います。これが期待どおりに機能していることの証拠として、このバインディングから生成されたクラス(Cust)が表示され、common.xsdによって生成されたクラスによって再利用されます。生成された各クラスは、基本クラスjaxb.BaseMessageを実装します。

これは、XJCのバグが修正されるまで、あなたが見つけるのと同じくらい良い解決策だと思います。

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

<?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

<?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

<?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

<?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>
4
vallismortis

あなたが達成しようとしていることはベンダー拡張なしで可能であると私は信じているので、私は2番目の答えを投稿しますが、私の元の答えはベンダー拡張を必要とする他の人にも役立つかもしれないと思います。

この例では名前空間も削除されますが、簡単に追加し直すことができます。この回答には、前の回答と同じビルドスクリプトが使用されています。

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

<?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

<?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

<?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>
2
vallismortis

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>
1
lexicore