16

JAXBを使用するこのAPIを使用して、XJC(XML-to-Java)コンパイラーによってXMLスキーマから名前付き参照を介して生成されたオブジェクトモデルを便利に使用できます。これは、JAXBコンテキストの作成を抽象化し、あらゆる種類のバックグラウンドマジックとリフレクションによってObjectFactoryメソッドを見つけ出します。その基本的な要点は、常に1つの一般的なスキーマを定義し、次にその一般的なスキーマを「拡張」する任意の数(0の場合もある)のスキーマを定義し、それぞれが独自のデータモデルを作成することです。一般的なスキーマには再利用可能な定義があり、それを拡張するスキーマはそれらを使用して独自のモデルを構成します。

現在、複数のプロジェクトで一般的なスキーマを再利用したいという状況に遭遇しました。一般的な型の定義はプロジェクト間で同じである必要があり、一部のコードはそれらから生成された抽象クラスに対して構築されます。したがって、最初にいくつかの汎用スキーマのクラスを生成し、次にそれらを拡張して個別に使用するクラスを生成する必要があります。ビルドプロセスにMavenを使用しています。

私が直面している問題は、拡張スキーマ内のそのジェネリックスキーマから型定義を解決することです。

私の汎用スキーマの名前が「general.xsd」で、次のようになっているとします。

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.foobar.com/general"
xmlns:gen="http://www.foobar.com/general"
elementFormDefault="qualified" attributeFormDefault="qualified">

    <!-- Element (will usually be root) -->
    <xs:element name="transmission" type="gen:Transmission" />

    <!-- Definition -->
    <xs:complexType name="Transmission" abstract="true">
        <xs:sequence>
            <!-- Generic parts of a transmission would be in here... -->
        </xs:sequence>
    </xs:complexType>

</xs:schema>

その隣に、名前のカスタマイズを行い、出力のパッケージ名を設定するためのバインディングファイルがあります。

<?xml version="1.0" encoding="UTF-8"?>
<bindings xmlns="http://java.sun.com/xml/ns/jaxb" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
    version="2.1">

    <!-- Bindings for the general schema -->
    <bindings schemaLocation="general.xsd" node="/xs:schema">

        <schemaBindings>
            <package name="com.foobar.models.general"/>
        </schemaBindings>

        <bindings node="//xs:complexType[@name='Transmission']">
            <!-- Some customization of property names here... -->
        </bindings>

</bindings>

次に、そのプロジェクトのPOMに次のビットを入れて、Javaクラスを生成します。

<plugin>
    <groupId>org.jvnet.jaxb2.maven2</groupId>
    <artifactId>maven-jaxb21-plugin</artifactId>
    <version>0.8.0</version>
    <executions>
        <execution>
            <id>xjc-generate</id>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <schemaDirectory>${basedir}/src/main/resources/com/foobar/schemas</schemaDirectory>
                <schemaLanguage>XMLSCHEMA</schemaLanguage>
                <addCompileSourceRoot>true</addCompileSourceRoot>
                <episode>true</episode>
                <removeOldOutput>true</removeOldOutput>
            </configuration>
        </execution>
    </executions>
</plugin>

ご覧のとおり、私はJAXB2.1Mavenプラグインを使用しています。段階的なコンパイルのためにエピソードファイルを生成するオプションを設定しました。以前の出力を削除するオプションは、バグの回避策でした。最初にすべてがクリーンアップされていることを確認して、再コンパイルを強制するだけです。

ここまでは順調ですね。そのプロジェクトは問題なくコンパイルされます。生成されたJavaクラスとは別に、スキーマを結果のjarファイルにパッケージ化することにも注意してください。したがって、それらはクラスパスで利用できます。ファイルは、sun-jaxb.episode本来あるべきMETA-INFにあります。

次に、最初にインポートすることにより、上記を拡張するスキーマを使用するプロジェクトを開始します。「サブタイプ」の1つは次のようになります(これをsub.xsdと呼びます)。

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.foobar.com/sub"
xmlns:sub="http://www.foobar.com/sub"
xmlns:gen="http://www.foobar.com/general"
elementFormDefault="qualified" attributeFormDefault="qualified">

    <xs:import namespace="http://www.foobar.com/general" />

    <!-- Definition -->
    <xs:complexType name="SubTransmission">
        <xs:complexContent>
            <xs:extension base="gen:Transmission">
                <xs:sequence>
                    <!-- Additional elements placed here... -->
                </xs:sequence>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>

</xs:schema>

ここでも、バインディングファイルがあります。

<?xml version="1.0" encoding="UTF-8"?>
<bindings xmlns="http://java.sun.com/xml/ns/jaxb" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
    version="2.1">

    <!-- Bindings for sub type -->
    <bindings schemaLocation="sub.xsd" node="/xs:schema">

        <schemaBindings>
            <package name="com.foobar.models.sub"/>
        </schemaBindings>

    </bindings>

</bindings>

そして、XJC生成を処理するこのプロジェクトのPOMからのビットは次のとおりです。

<plugin>
    <groupId>org.jvnet.jaxb2.maven2</groupId>
    <artifactId>maven-jaxb21-plugin</artifactId>
    <version>0.8.0</version>
    <executions>
        <execution>
            <id>xjc-generate</id>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <schemaDirectory>${basedir}/src/main/resources/com/foobar/schemas</schemaDirectory>
                <schemaLanguage>XMLSCHEMA</schemaLanguage>
                <addCompileSourceRoot>true</addCompileSourceRoot>
                <episode>false</episode>
                <catalog>${basedir}/src/main/resources/com/foobar/schemas/catalog.cat</catalog>
                <episodes>
                    <episode>
                        <groupId>com.foobar</groupId>
                        <artifactId>foobar-general-models</artifactId>
                        <version>1.0.0-SNAPSHOT</version>
                        <scope>compile</scope>
                    </episode>
                </episodes>
                <removeOldOutput>true</removeOldOutput>
            </configuration>
        </execution>
    </executions>
</plugin>

元々、すべてのスキーマは1つのフォルダーにありschemaLocation、インポートの属性をに設定してgeneral.xsdいましたが、これは正常に機能しました。しかし、物事がプロジェクト間で分離された今、私は問題にぶつかります。最初の問題は、他のスキーマが見つからなかったことです。これを解決schemaLocationするには、<xs:import />要素から属性を削除し、属性のみを保持し、上記のPOM抽出で参照されてnamespaceいるカタログファイル()を追加します。catalog.catその内容は次のとおりです。

PUBLIC "http://www.foobar.com/general" "classpath:/com/foobar/schemas/general.xsd"

スキーマが見つからないことを示すエラーが発生しなくなったため、これは機能しているようです。しかし、何らかの理由で、インポートされたスキーマからの実際の型定義の解決は引き続き失敗します。例外は次のとおりです。

Error while parsing schema(s).Location [ file:/C:/NetBeans_groups/Test/SubModelBundle/src/main/resources/com/foobar/schemas/sub.xsd{...,...}].
org.xml.sax.SAXParseException: src-resolve: Cannot resolve the name 'gen:Transmission' to a(n) 'type definition' component.

これが私がこれまでに試したことです:

  • カタログファイルを使用します。インポートされたスキーマが見つかるようになったため、部分的に成功しました。
  • 一般スキーマのコンパイルでエピソードファイルを生成し、これをサブスキーマのコンパイルに使用します。違いはないようですが、これはタイプが解決された後にのみ役割を果たすはずなので、これはまだ重要ではないと思います。
  • 別のJAXP(注:JAXB、JAXPではない)実装を使用してください。例外のスタックトレースでそれを確認できたので、別のものを使用しましたが、最終結果は同じです。
  • maven-jaxb22-plugin21の代わりに使用してください。違いはありません。

オンラインで見てみると、少なくとも2006年以来、人々はこの問題に遭遇しているようであり、Xercesリゾルバーの問題に関連している可能性があります。これが、誰も気にせずに6年間潜んでいるバグではないことを願っています。他の誰かがいくつかの提案がありますか?たぶん誰かが同じ問題に遭遇し、解決策を見つけましたか?私が考えることができる唯一の回避策は、「svn:externals」を使用して一般的なスキーマをサブプロジェクトにドラッグし、そこでクラスを再生成することですが、それはダーティであり、svnリポジトリに接続できる場合にのみ機能します。

この長い投稿を読んでくれてありがとう。上記のすべてを既存のプロジェクトから取り除いて、匿名性のためにいくつかの名前空間やその他のものを置き換えたことを覚えておいてください。そのため、いくつかのタイプミスが発生する可能性があります。

4

2 に答える 2

4

この回答は編集されました。以前は、カスタムカタログリゾルバーを使用したソリューションがありました。しかし、私は今実際の問題を見つけました。説明は次のとおりです。解決策を提供するTL;DRバージョンについては、この回答の一番下までスクロールしてください。


問題はカタログファイルにあります。この行がどのようにあったかに注意してください。

PUBLIC "http://www.foobar.com/general" "classpath:/com/foobar/schemas/general.xsd"

それは何を言いますか?パブリックIDhttp://www.foobar.com/generalが検出された場合、スキーマのシステムIDはですclasspath:/com/foobar/schemas/general.xsd。ここまでは順調ですね。schemaLocation要素から属性を削除した場合<xs:import />、残るのはパブリックID(名前空間URN)だけであり、カタログファイルはそのスキーマの場所を示します。

この問題は、そのスキーマが<xs:include />要素を使用するときに発生します。それらには、同じターゲット名前空間を持つスキーマファイルが含まれます。システムID(相対的な場所)を指定します。したがって、解決に使用されることを期待します。ただし、カタログリゾルバーへの呼び出しをログに記録すると、パブリックID(名前空間)とシステムID(相対的な場所)の両方を使用して解決の要求が行われていることがわかります。そして、それはそれがうまくいかないところです。カタログファイルにバインドされているため、パブリックIDが優先されます。general.xsdそして、それは私たちを再びファイルに直接導きます。

たとえば、一般的なスキーマは次のとおりです。

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.foobar.com/general"
xmlns:gen="http://www.foobar.com/general"
elementFormDefault="qualified" attributeFormDefault="qualified">

    <!-- Including some definitions from another schema in the same location -->
    <xs:include schemaLocation="simple-types.xsd" />

    <!-- Remaining stuff... -->

</xs:schema>

そして、それを使用するスキーマは次のとおりです。

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.foobar.com/sub"
xmlns:sub="http://www.foobar.com/sub"
xmlns:gen="http://www.foobar.com/general"
elementFormDefault="qualified" attributeFormDefault="qualified">

    <xs:import namespace="http://www.foobar.com/general" />

    <!-- Remaining stuff... -->

</xs:schema>

XJCがその最後のスキーマを解析しているとき、これは次のように発生します。

  1. ローカル定義の解析。
  2. インポートされたスキーマからの定義への参照が発生します。
  3. インポートをチェックし、システムIDを検出せず、パブリックID(http://www.foobar.com/general)のみを検出します。
  4. カタログをチェックします。
  5. パブリックIDのへのバインドを検索しclasspath:/com/foobar/schemas/general.xsdます。
  6. インポートされたスキーマの定義を解析します。
  7. 含まれているスキーマ(simple-types.xsd)からの定義への参照が発生します。
  8. チェックインクルード、システムIDの検索。
  9. カタログでシステムIDを確認しますが、パブリックIDは暗黙的です。
  10. パブリックIDのへのバインドを検索classpath:/com/foobar/schemas/general.xsdします。これはシステムIDよりも優先されます。
  11. 含まれているスキーマ定義の解決に失敗します。

解決が試行される順序の詳細は、XMLカタログのOASIS仕様に記載されています:https ://www.oasis-open.org/committees/entity/spec.html#s.ext.ent 。少し解釈が必要ですが、解決の優先方法がパブリックIDである場合、システムIDが存在する場合でも、カタログファイルにバインドされるときにそれらが優先されることがわかります。

したがって、解決策は、システムIDが解決の優先方法であることを指定し、インポートでシステムIDを提供しないことです。これにより、カタログのパブリックIDバインディングが使用され、インクルードからの相対システムIDに依存します。OASIS XMLカタログ形式では、属性を使用できますprefer="system"。OASIS TR9401カタログ形式では、を使用できますOVERRIDE no。どうやらデフォルトはpublic/yesです。

したがって、私のカタログファイルは次のようになります。

OVERRIDE no
PUBLIC "http://www.foobar.com/general" "classpath:/com/foobar/schemas/general.xsd"

これで、通常のカタログリゾルバーが正常に機能します。カスタムのものはもう必要ありません。ただし、スキーマを含めるときにパブリックIDが解決に使用され、システムIDよりも優先されるとは思いませんでした。パブリックIDはインポートにのみ使用され、解決に失敗した場合でもシステムIDが考慮されると思いました。カスタムリゾルバーにログを追加するだけで、これが明らかになりました。


簡単な答え:OVERRIDE noTR9401カタログファイルの最初のディレクティブとして追加するかprefer="system"、XMLカタログファイルに属性を追加します。schemaLocationディレクティブで指定しないでください<xs:import />。ただし、名前空間をカタログファイル内の適切なスキーマの場所にバインドしてください。<xs:include />含まれているスキーマへの相対パスを使用していることを確認してください。

もう1つの興味深い点は、XJCで使用されるカタログリゾルバーは、classpath:URIだけでなくmaven:、Mavenアーティファクトに関連して機能するURIも処理できることです。ビルドツールとして使用している場合は非常に便利です。 http://confluence.highsource.org/display/MJIIP/User+Guide#UserGuide-Usingcatalogs

于 2012-10-17T13:12:42.273 に答える
2

Maven 2.2.1の使用は、 org.jvnet.jaxb2.maven2.resolver.tools.ClasspathCatalogResolverを使用して機能します。

構成例は次のとおりです。

<plugin>
    <groupId>org.jvnet.jaxb2.maven2</groupId>
    <artifactId>maven-jaxb2-plugin</artifactId>
    <version>0.8.0</version>
    <executions>
        <execution>
            <id>executionId</id>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <schemaDirectory>src/main/resources/META-INF/schemas</schemaDirectory>
                <generatePackage>com.company.project.data</generatePackage>
                <bindingDirectory>src/main/jaxb</bindingDirectory>
                <catalog>src/main/jaxb/catalog.cat</catalog>
                <catalogResolver>org.jvnet.jaxb2.maven2.resolver.tools.ClasspathCatalogResolver</catalogResolver>
                <verbose>false</verbose>
                <extension>true</extension>
                <episodes>
                    <episode>
                        <groupId>com.company.project</groupId>
                        <artifactId>xsd-common-types</artifactId>
                        <version>${xsd-common-types.version}</version>
                    </episode>
                </episodes>
            </configuration>
        </execution>
    </executions>
    <dependencies>
        <dependency>
            <groupId>com.company.project</groupId>
            <artifactId>xsd-common-types</artifactId>
            <version>${xsd-common-types.version}</version>
        </dependency>
    </dependencies>
</plugin>

この構成をMaven3で機能させると、org.xml.sax.SAXParseExceptionが発生します。

于 2013-02-27T04:15:13.447 に答える