2011-07-15 16 views
3

Webサービス用のアダプタを開発している間、私はこのような応答直面終わっている:複数のXML「ファイル」

<?xml version="1.0" encoding="UTF-8"?> 
<ResponseHeader version="1.0"> 
    <ResponseCode>T100</ResponseCode> 
    <SubmissionIdentifier>1</SubmissionIdentifier> 
</ResponseHeader> 

<?xml version="1.0" encoding="UTF-8"?> 
<SubmissionProgress xmlns="sss" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
    status="inProgress" 
    submissionIdentifier="1" 
    submissionType="live"> 
    <PFile status="rejected" 
     index="1" 
     pFileIdentifier="999"> 
     <Exception errorCode="2001" outcomeType="rejectFile"> 
      <Description>There.file. </Description> 
      <SourceRecord index="3">...</SourceRecord> 
     </Exception> 
    </PFile> 
</SubmissionProgress> 

ResponseHeaderSubmissionProgress(および内部のすべての要素を)クラスがxjcによって正常に生成されました。もしこの文字列を2つの異なる文字列に分割すると、両方のクラスを完全にアンマーシャリングできます。
しかし、私はそれを同じStringに保持し、それを両方のアンマーシャラーに順番に渡そうとすると、最初のアンマーシャルでブレークします。
私は1つの文字列の両方からアンマーシャリングするためにこのコードを使用しています:

Reader reader = new StringReader(response); 
JAXBContext jcrh = JAXBContext.newInstance(ResponseHeader.class); 
JAXBContext jcsp = JAXBContext.newInstance(SubmissionProgress.class); 
Unmarshaller urh = jcrh.createUnmarshaller(); 
Unmarshaller usp = jcsp.createUnmarshaller(); 
ResponseHeader rh = (ResponseHeader) urh.unmarshal(reader); 
SubmissionProgress sr = (SubmissionProgress) usp.unmarshal(reader); 

そして、私は次の例外(でResponseHeader RH =(ResponseHeader)urh.unmarshal(リーダー);)を取得:

[email protected] 
javax.xml.bind.UnmarshalException 
- with linked exception: 
[org.xml.sax.SAXParseException: The processing instruction target matching "[xX][mM][lL]" is not allowed.] 
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.createUnmarshalException(AbstractUnmarshallerImpl.java:315) 
(...) 

このような場合(複数のXMLファイルを1つのストリームで使用する)にはいくつかのJAXB調整がありますか?

答えて

0

JAXB自身がファイルを読み込む方法がないため、2つの解決策が見つかりました。

最初と1単純なケースで流れが小さく、大きなとクリーンなコードと将来の使用のために、1つの文字列にそれをすべて読んで、それを

String xml = "<?xml ... <?xml ..."; 
String[] xmlArray = xml.split("<\\?xml"); 
ObjectA a = (ResponseHeader) u.unmarshal(new StringReader("<?xml"+xmlArray[1]); 
ObjectB b = (SubmissionProgress) u2.unmarshal(new StringReader("<?xml"+xmlArray[2)); 

しかし、運動などを分割することですストリームが(一度に一つのオブジェクトを扱う)、Iは

MultiXMLDocReader xmlReader = new MultiXMLDocReader(new InputStreamReader(anyInputStream)); 
ObjectA a = (ResponseHeader) u.unmarshal(xmlReader); 
ObjectB b = (SubmissionProgress) u2.unmarshal(xmlReader); 
として容易に使用することができるMultiXMLDocReaderクラス

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.Reader; 

public class MultiXMLDocReader extends Reader { 
    private BufferedReader reader; 
    private String buffer; 
    private int bufferPos; 
    private boolean firstDocument; 
    private boolean realEOF; 
    private boolean enforceEOF; 

    public MultiXMLDocReader(Reader reader) { 
     this.reader = new BufferedReader(reader); 
     firstDocument = true; 
     buffer = ""; 
     bufferPos = 0; 
     realEOF = enforceEOF = false; 
    } 

    @Override 
    public void close() throws IOException { 
     enforceEOF = false; 
     if (realEOF) reader.close(); 
    } 

    @Override 
    public int read() throws IOException { 
     char[] buffer = new char[1]; 
     int result = read(buffer, 0, 1); 
     if (result < 0) return -1; 
     return buffer[0]; 
    } 

    @Override 
    public int read(char[] cbuf, int off, int len) throws IOException { 
     if (enforceEOF) return -1; 
     int lenLeft = len; 
     int read = 0; 
     while (lenLeft > 0) { 
      if (buffer.length()>0) { 
       char[] lbuffer = buffer.toCharArray(); 
       int bufLen = buffer.length() - bufferPos; 
       int newBufferPos = 0; 
       if (lenLeft < bufLen) { 
        bufLen = lenLeft; 
        newBufferPos = bufferPos + bufLen; 
       } 
       else buffer = ""; 
       System.arraycopy(lbuffer, bufferPos, cbuf, off, bufLen); 
       read += bufLen; 
       lenLeft -= bufLen; 
       off += bufLen; 
       bufferPos = newBufferPos; 
       continue; 
      } 
      buffer = reader.readLine(); 
      if (buffer == null) { 
       realEOF = true; 
       enforceEOF = true; 
       return (read == 0 ? -1 : read); 
      } 
      else 
       buffer += "\n"; 
      if (buffer.startsWith("<?xml")) { 
       if (firstDocument) firstDocument = false; 
       else { 
        enforceEOF = true; 
        return (read == 0 ? -1 : read); 
       } 
      } 
     } 
     return read; 
    } 
} 

を作っ

ストリーム全体を文字列にロードすることなく

2

私はJAXBの微調整について知らない。私がこのようなことをしたのは、必要に応じてドキュメントの終わりをシミュレートするXmlEventReader(またはXmlStreamReader)を実装することです。 Unmarshaller.unmarshal()はこれらのうちの1つを引数として取ることに注意してください。イベントシーケンスを正しく取得するには、「通常の」ドキュメントのイベントシーケンスを見てください。 2つの非マーシャル()を行います。

+1

クイックレスポンス、ありがとうございました。何か簡単なことがあれば、いくつかのコードで詳しく説明できますか?イベントシーケンス(ストリーム内のXMLファイルの順序である場合)は常に同じであり、実際にはそれがあります。 –

+0

私は何かをまとめる時間がありません。 [このフィルタ](http://stackoverflow.com/questions/277502/jaxb-how-to-ignore-namespace-during-unmarshalling-xml-document)を参照してください。それは別のことをしていますが、文書の最後のシミュレーションでドロップできる全体的なデザインを十分に理解できます。 –

+1

確かに、ドキュメントの最後にどこにドロップしたいかを検出することができました。ちょうど今それを落とす方法を逃した。 –

関連する問題