【问题标题】:Multiple XML "files" in one stream一个流中的多个 XML“文件”
【发布时间】:2011-07-15 18:45:05
【问题描述】:

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

<?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(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 文件)?

【问题讨论】:

    标签: java xml-serialization jaxb


    【解决方案1】:

    我不知道 JAXB 调整;我做这种事情的方式是实现一个 XmlEventReader(或 XmlStreamReader),在需要时模拟文档结束。请注意, Unmarshaller.unmarshal() 将其中一个作为参数。为确保您获得正确的事件序列,请查看“正常”文档的事件序列。你会做两个 unmarshal()s。

    【讨论】:

    • 感谢您的快速回复,Ed。如果它很简单,你能用一些代码详细说明吗?事件顺序(如果这是流中 XML 文件的顺序)总是相同的,我确实有。
    • 我没有时间整理一些东西。您可能想查看this filter。它正在做一些不同的事情,但希望能让您对整体设计有足够的了解,您可以将其放入文档结尾模拟中
    • 确实它给了我足够的信息来检测我想在文档末尾放置的位置。只是想念现在如何放下它。
    【解决方案2】:

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

    但是,作为一个练习,为了更简洁的代码和将来使用更大的流(一次处理一个对象),我创建了 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);
    

    无需将整个流加载到字符串中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-07
      • 1970-01-01
      • 1970-01-01
      • 2018-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多