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

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

问题描述

在为 Web 服务开发适配器时,我最终遇到了这样的响应:

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>

ResponseHeaderSubmissionProgress(以及其中的每个元素)类已由 xjc 成功生成,如果我将此字符串拆分为 2 个不同的字符串,我可以完美地解组这两个类.
但是,如果我将它保存在同一个字符串中并尝试将它依次传递给两个解组器,它会在第一个解组器中中断.
我正在使用此代码从一个字符串中解组两者:

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

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天全站免登陆