Multiple XML “files” in one stream

前端 未结 2 996
离开以前
离开以前 2020-12-18 13:51

While developing an adapter for a webservice, I\'ve ended up facing a response like this:




        
相关标签:
2条回答
  • 2020-12-18 14:01

    I don't know of a JAXB tweak; the way I've done this kind of thing is to implement an XmlEventReader (or XmlStreamReader) that simulates end-of-document when needed. Note that Unmarshaller.unmarshal() will take one of these as an argument. To make sure you get the event sequence right, watch a "normal" document's event sequence. You'll do two unmarshal()s.

    0 讨论(0)
  • 2020-12-18 14:02

    As there is no way for JAXB to read through the files by itself, I've found 2 working solutions.

    The first and simpler one, in case the stream is small, would be to read it all into one string and split it

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

    But, as an exercise, for cleaner code and future use with bigger streams (dealing with one object at a time), I made MultiXMLDocReader class

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

    which can be used as easily as

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

    without loading the whole stream to a string.

    0 讨论(0)
提交回复
热议问题