2017-08-17 9 views
0

私はルート要素がリストであるXMLを解析する必要があります。私はむしろ、のようなものを書いて、ユーザーが非整列リスト全体をメモリに保持し、それを1つずつ処理するよう強制しません。JAXBパースXMLリストの順番(一つずつ)

は、これまでのところ私は内部Iterable<SomeObject>と私自身のIteratorを実装して、このようなクラスを書いた:

public class SomeObjectsIterableParser implements Iterable<SomeObjectType> { 

    private final Unmarshaller jaxbUnmarshaller; 
    private final XMLStreamReader xmlReader; 

    public SomeObjectsIterableParser(Schema schema, java.io.Reader xmlStringReader) throws ExtractorException { 
    try { 
     jaxbUnmarshaller = JAXBContext.newInstance(SomeObjectType.class).createUnmarshaller(); 
     xmlReader = XMLInputFactory.newFactory().createXMLStreamReader(xmlStringReader); 
    } catch (JAXBException | XMLStreamException e) { 
     throw new ExtractorException("Could not create jaxbUnmarshaller", e); 
    } 
    jaxbUnmarshaller.setSchema(schema); //turns on schema validation 

    //Move reader to first occurence of SomeObject - really necessary? 
    try { 
     while (xmlReader.hasNext()) { 
     if (!xmlReader.isStartElement() || !xmlReader.getLocalName().equals("SomeObject")) 
      xmlReader.next(); 
     else break; 
     } 
    } catch (XMLStreamException e) { 
     e.printStackTrace(); 
    } 

    } 

    @Override 
    public Iterator<SomeObjectType> iterator() { 
    return new MyIterator(); 
    } 

    class MyIterator implements Iterator<SomeObjectType> { 

    @Override 
    public boolean hasNext() { 
     try { 
     return xmlReader.hasNext(); 
     } catch (XMLStreamException e) { 
     throw new RuntimeException(e); 
     } 
    } 

    @Override 
    public SomeObjectType next() { 
     try { 
     return (SomeObjectType) jaxbUnmarshaller.unmarshal(xmlReader); 
     } catch (JAXBException | XMLStreamException e) { 
     throw new RuntimeException(e); 
     } 
    } 

    @Override 
    public void remove() { 
     throw new UnsupportedOperationException("Not supported yet"); 
    } 
    } 
} 

私はメッセージとnext()方法で例外を受け取る:org.xml.sax.SAXParseException; lineNumber: 2; columnNumber: 17; cvc-elt.1: Cannot find the declaration of element 'SomeObject'.

は私が間違って何をしているのですか?

+1

完全な診断を行うにはすべてが必要ですが、おそらくの子としてのみ宣言され、このスキーマでは許容できるスタンドアロン要素ではありません。あなたのUnmarshallerはあなたのXMLReaderがこれまでに読んだことを見ないので、が実際にの子であることを知ることはできません。このような要素を独立して宣言するには、スキーマを別に宣言するか、別の方法で検証する必要があります(私には分かりません) – kumesana

+0

@kumesanaあなたは正しいですが、これが問題でした(ただし唯一ではありません)。私は接続された質問を作成しました:https://stackoverflow.com/questions/45733478/jaxb-schema-validation-when-unmarshalling-non-root-element – jaskmar

答えて

0

私がしたいことを説明するthe articleが見つかりました。その結果、私はそのようなコードを書いた:

public class SomeObjectsIterableParser implements Iterable<SomeObjectType> { 

    private final Unmarshaller jaxbUnmarshaller; 
    private final XMLStreamReader xmlReader; 

    public SomeObjectsIterableParser(Schema schema, Reader SomeObjectResponse) throws ExtractorException { 
    try { 
     jaxbUnmarshaller = JAXBContext.newInstance(SomeObjectType.class).createUnmarshaller(); 
     xmlReader = XMLInputFactory.newFactory().createXMLStreamReader(SomeObjectResponse); 
    } catch (JAXBException | XMLStreamException e) { 
     throw new ExtractorException("Could not create jaxbUnmarshaller", e); 
    } 
    //jaxbUnmarshaller.setSchema(schema); //schema can handle only root element 
    advanceReaderToFirstProfile(); 
    } 

    private void advanceReaderToFirstProfile() { 
    try { 
     xmlReader.nextTag(); 
     while(!xmlReader.getLocalName().equals("SomeObject")) { 
     xmlReader.nextTag(); 
     } 
    } catch (XMLStreamException e) { 
     e.printStackTrace(); 
    } 
    } 

    @Override 
    public Iterator<SomeObjectType> iterator() { 
    return new MyIterator(); 
    } 

    class MyIterator implements Iterator<SomeObjectType> { 

    @Override 
    public boolean hasNext() { 
     try { 
     if (xmlReader.isWhiteSpace() && xmlReader.hasNext()) { 
      //ommit witespaces 
      xmlReader.nextTag(); 
     } 
     } catch (XMLStreamException e) { 
     throw new RuntimeException(e); 
     } 
     return xmlReader.isStartElement() 
      && xmlReader.getLocalName().equals("SomeObject"); 
    } 

    @Override 
    public SomeObjectType next() { 
     try { 
     JAXBElement<SomeObjectType> element = jaxbUnmarshaller.unmarshal(xmlReader, SomeObjectType.class); 
     return element.getValue(); 
     } catch (JAXBException | XMLStreamException e) { 
     throw new RuntimeException(e); 
     } 
    } 

    @Override 
    public void remove() { 
     throw new UnsupportedOperationException("Not supported yet"); 
    } 
    } 
} 

は3の点に注意して考えて:

  1. スキーマ検証root以外の要素に適用することはできません。関連する質問hereがあります。
  2. 使用構文:
    JAXBElement<SomeObjectType> element = jaxbUnmarshaller.unmarshal(xmlReader, SomeObjectType.class);
    代わりの
    (SomeObjectType) jaxbUnmarshaller.unmarshal(xmlReader);。リンクされた例外でjavax.xml.bind.UnmarshalException

    • java.lang.RuntimeException:
      は、そうでなければ、例外を受け取る
      [com.sun.istack.internal.SAXParseException2。 lineNumber:2; columnNumber:22;予期しない要素(uri: ""、ローカル: "SomeObject")。期待される要素は(none)]

  3. 例よりも注意深く例外を処理します。 IterableおよびIteratorインターフェイスでは、実行時以外の例外をスローすることはできません。
関連する問題