Несколько XML-файлов в одном потоке - PullRequest
3 голосов
/ 15 июля 2011

При разработке адаптера для веб-службы я столкнулся с таким ответом:

<?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.
Я использую этот код, чтобы удалить обе строки из одной строки:

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 в одном потоке)?

Ответы [ 2 ]

2 голосов
/ 15 июля 2011

Я не знаю настройки JAXB; способ, которым я сделал это, заключается в реализации XmlEventReader (или XmlStreamReader), который имитирует конец документа при необходимости. Обратите внимание, что Unmarshaller.unmarshal () примет один из них в качестве аргумента. Чтобы убедиться в правильности последовательности событий, просмотрите последовательность событий «нормального» документа. Вы сделаете два unmarshal () s.

0 голосов
/ 27 июля 2011

Поскольку 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);

без загрузки всего потока в строку.

...