2011-07-15 88 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個不同的字符串,我可以完美地解組這兩個類。
但是,如果我將它放在同一個字符串中,並嘗試按順序將它傳遞給兩個拆分器,它將在第一個拆分器中斷開。
我使用此代碼從一個字符串中解組兩個:

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) 
(...) 

是否有一些JAXB調整在這些情況下使用(多個XML文件在一個單一的流)?

回答

0

由於JAXB沒有辦法自己讀取文件,所以我找到了2個工作解決方案。

第一和簡單的一個,萬一流小,將它全部讀入一個字符串,並把它分解

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

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; 
    } 
} 

可作爲容易用作

MultiXMLDocReader xmlReader = new MultiXMLDocReader(new InputStreamReader(anyInputStream)); 
ObjectA a = (ResponseHeader) u.unmarshal(xmlReader); 
ObjectB b = (SubmissionProgress) u2.unmarshal(xmlReader); 

沒有將整個流加載到字符串。

2

我不知道JAXB的調整;我做這種事情的方式是實現一個XmlEventReader(或XmlStreamReader),它在需要時模擬文檔結束。請注意,Unmarshaller.unmarshal()會將其中的一個作爲參數。爲了確保正確地獲取事件序列,請觀察「正常」文檔的事件序列。你會做兩個unmarshal()。

+1

感謝您的快速反應,埃德。你能否詳細說明一些代碼是否簡單?事件序列(如果這是流內XML文件的順序)總是相同的,我確實是這樣。 –

+0

我沒有時間把東西放在一起。你可能想看看[這個過濾器](http://stackoverflow.com/questions/277502/jaxb-how-to-ignore-namespace-during-unmarshalling-xml-document)。它正在做一些不同的事情,但希望能給你足夠的整體設計感,你可以在文檔末仿真中加入 –

+1

的確如此,它足以讓我檢測到我想在文檔的最後放置的位置。現在想想如何放棄它。 –