多个XML“文件”在一个流中 [英] Multiple XML "files" in one stream

查看:159
本文介绍了多个XML“文件”在一个流中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在为webservice开发适配器时,我最终面临这样的响应:

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

<?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>

ResponseHeader SubmissionProgress (以及每个元素)在内部)类已经由xjc成功生成了,如果我将这个字符串拆分为2个不同的字符串,我可以完全解组这两个类。

但是,如果我将它保存在同一个字符串中并尝试将其传递给两个unmarshallers顺序它在第一个unmarshall中打破。

我正在使用此代码从一个字符串解组:

ResponseHeader and SubmissionProgress (and every element inside) classes have been successfully generated by xjc and, if I split this string into 2 different string I can unmarshall both classes perfectly.
But, if I keep it in the same String and try to pass it to both unmarshallers sequentially it breaks in the first unmarshall.
I'm using this code to unmarshall both from one String:

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(读者); ):

And I get the following exception (at ResponseHeader rh = (ResponseHeader) urh.unmarshal(reader);):

uk.co.bacs.submissions.ResponseHeader@fced4
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文件)?

Is there some JAXB tweak to use in these cases (multiple XML files in one single stream)?

推荐答案

由于JAXB无法自行读取文件,因此我找到了2个可行的解决方案。

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

但是,作为练习,更清洁的代码和未来使用更大的流(一次处理一个对象),我做了MultiXMLDocReader类

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

可以轻松使用

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.

这篇关于多个XML“文件”在一个流中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆