在为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>
ResponseHeader和SubmissionProgress(以及里面的每个元素)类已经由xjc成功生成,如果我将这个字符串分成两个不同的字符串,我可以完美地分解这两个类。但是,如果我将它保存在同一个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);
我得到以下异常(at ResponseHeader rh = (ResponseHeader) ur .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)
(...)
在这些情况下(单个流中有多个XML文件)是否有一些JAXB调整可以使用? 我不知道JAXB的调整;我做这类事情的方法是实现一个xmlleventreader(或XmlStreamReader),它在需要时模拟文档结束。注意Unmarshaller.unmarshal()将接受其中一个作为参数。为了确保获得正确的事件序列,请观察"正常"文档的事件序列。您将执行两次unmarshal()操作。
由于JAXB本身无法读取文件,因此我找到了两个可行的解决方案。
如果流很小,第一个也是更简单的方法是将其全部读入一个字符串并将其拆分
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);