3

以下のコードは、一度に 1 オブジェクトずつストリームから XML をアンマーシャリングするために正しく機能します。

しかし、unmarshaller.setSchema(schema)行のコメントを外すと、プログラムは例外をスローします:

[org.xml.sax.SAXParseException: cvc-elt.1: 要素 'Subscriber' の宣言が見つかりません。]

クラスを使用して既に XML を検証しましたjavax.xml.validation.Validatorが、私の目標は、一度に 1 要素ずつ、検証とアンマーシャリングを同時に行うことです。

これは私の現在のコードです:

SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); 
Schema schema = sf.newSchema(new File("/Path to xsd"));

XMLInputFactory inputFactory = XMLInputFactory.newInstance();
XMLStreamReader streamReader = inputFactory.createXMLStreamReader(new FileReader("/Path to xml"));

JAXBContext jaxbContext = JAXBContext.newInstance(SubscriberType.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
//unmarshaller.setSchema(schema);

streamReader.nextTag();
streamReader.require(XMLStreamConstants.START_ELEMENT, null, "Subscribers");
streamReader.nextTag();    
while (streamReader.getEventType() == XMLStreamConstants.START_ELEMENT) {

    JAXBElement<SubscriberType> pt = unmarshaller.unmarshal(streamReader, SubscriberType.class);
    //do something with the unmarshalled object pt...store to db ect.

    if (streamReader.getEventType() == XMLStreamConstants.CHARACTERS) {
        streamReader.next();
    }
}

私のスキーマsubscriber.xsdの抜粋:

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

  <xsd:element name="Subscribers" type="SubscriberType" />

  <xsd:complexType name="SubscriberType">
    <xsd:sequence>
      <xsd:element name="Subscriber" 
              type="SubscriberInformation" 
              minOccurs="1" 
              maxOccurs="unbounded"/>
    </xsd:sequence>
  </xsd:complexType>
4

1 に答える 1

1

次のようなスキーマで試してください。

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

    <xsd:element name="Subscribers" type="SubscriberType"/>

    <xsd:element name="Subscriber" type="SubscriberInformation" />

    <xsd:complexType name="SubscriberType">
        <xsd:sequence>
            <xsd:element ref="Subscriber" minOccurs="1" maxOccurs="unbounded"/>
        </xsd:sequence>
    </xsd:complexType>

あなたのスキーマで起こると私が信じているのは、JAXB コンテキストはSubscriberTypeとのクラスを知っているということSubscriberInformationです。<Subscribers>ルート要素を持つ XML ドキュメントを渡した場合、SubscriberType. ただし、ルート要素を含む XML ドキュメントを渡した場合、通常、XJC によって生成され<Subscriber>たクラスでこの要素定義を見つけることはできません。ObjectFactoryしかしunmarshal、2 番目の引数、つまり期待しているクラスを取るメソッドを使用したので、アンマーシャラーに入力をSubscriberType. 結果は空のSubscriberTypeインスタンスになります。

ここで、<Subscriber>要素を 1 つずつ反復処理しているため (少なくとも、それがあなたが意図していることだと私が収集したことです)、アンマーシャラーにとっては、それをルート要素として XML ドキュメントを受け取っているように見えます。クラス引数を使用して型を把握するタスクを取り除いたので、その定義が見つからないことについて不平を言うことはありません。しかし、検証のためにスキーマを添付した瞬間、事態は崩壊します。<Subscribers>バリデーターは、あなたが要素内にいることを知りません。完全な XML ドキュメントが必要です。そのため、要素宣言を探しに行きますが<Subscriber>、その要素は複合型内でのみ定義されているため、空になります。これはグローバル要素定義ではありません (つまり、スキーマ ルートの下にあるもの)。

そこで、ここでやるべきことは2つ。1 つは、上記のように要素を定義し<Subscriber>、それを複合型で参照することです。もう 1 つは、アンマーシャル呼び出しを変更してunmarshal(streamReader, SubscriberInformation.class)、正しいタイプのオブジェクトを取得することです。streamReader.next()への呼び出しが条件にあり、起動しない可能性があるため、無限ループまたは不適切なアンマーシャリングにも注意してください。

JAXB を念頭に置いてスキーマを記述するには、特定のスタイルが必要です。一般に、要素をグローバルに定義してから参照するのが最善です。絶対にカプセル化されたままにする必要がある場合にのみ、複合型内で要素をローカルに定義します。

長々とした回答で申し訳ありません。私はよく起きていません:)

于 2011-08-18T12:05:44.810 に答える