我一直在使用JAXB一段时间来解析看起来像这样的xml:
<report> <-- corresponds to a "wrapper" object that holds
some properties and two lists - a list of A's and list of B's
<some tags with> general <info/>
...
<A> <-- corresponds to an "A" object with some properties
<some tags with> info related to the <A> tag <bla/>
...
<A/>
<B> <-- corresponds to an "B" object with some properties
<some tags with> info related to the <B> tag <bla/>
...
</B>
</report>
负责编组xml的方面很糟糕但不受我的控制
它经常发送无效的xml字符和/或格式错误的xml
我和负责人交谈并修复了很多错误,但有些错误似乎无法修复
我希望我的解析器尽可能地对这些错误感到宽恕,并且当它不可能时,从错误的xml中获取尽可能多的信息。
因此,如果xml包含100个A并且其中一个有问题,我仍然希望能够保留其他99个。
这些是我最常见的问题:
1. Some info tag inner value contains invalid chars
<bla> invalid chars here, either control chars or just &>< </bla>
2. The root entity is missing a closing tag
<report> ..... stuff here .... NO </report> at the end!
3. An inner entity (A/B) is missing it's closing tag, or it's somehow malformed.
<A> ...stuff here... <somethingMalformed_blabla_A/>
OR
<A> ... Something malformed here...</A>
我希望我能很好地解释自己
我真的希望从这些xml中获取尽可能多的信息,即使它们有问题
我想我需要采用一些使用stax / sax和JAXB的策略,但我不确定如何。
如果100 A,一个A有xml问题,我不介意扔掉那个A.
虽然如果我能得到一个具有尽可能多的数据的A对象,可以解析直到错误,这会好得多。
答案 0 :(得分:2)
XML的哲学是XML的创建者负责创建格式良好的XML,收件人不负责在到达时修复错误的XML。 XML解析器需要拒绝格式错误的XML。还有其他“整洁”的工具可以将错误的XML转换为良好的XML,但是根据输入中的缺陷的性质,它们的工作效果是不可预测的。如果您将获得使用XML进行数据交换的好处,那么它需要格式良好。否则你也可以使用自己的专有格式。
答案 1 :(得分:2)
这个答案真的帮助了我:
JAXB - unmarshal XML exception
就我而言,我正在使用XML开关(-x)解析Sysinternals Autoruns工具的结果。要么是因为结果被写入文件共享,要么是因为某些错误的原因,新版本中的XML会在接近结尾时出错。由于此Autoruns捕获对于恶意软件调查至关重要,因此我真的想要数据。另外,我可以从文件大小中看出结果几乎已经完成。
当您拥有OP建议的包含许多子元素的文档时,链接问题中的解决方案非常有效。特别是,Autoruns XML输出非常简单,由许多“项目”组成,每个“项目”由许多带文本的简单元素组成(即由XJC生成的字符串属性)。因此,如果最后遗漏了一些项目,没什么大不了的......除非它当然与恶意软件有关。 :)
这是我的代码:
public class Loader {
private List<Exception> exceptions = new ArrayList<>();
public synchronized List<Exception> getExceptions() {
return new ArrayList<>(exceptions);
}
protected void setExceptions(List<Exception> exceptions) {
this.exceptions = exceptions;
}
public synchronized Autoruns load(File file, boolean attemptRecovery)
throws LoaderException {
Unmarshaller unmarshaller;
try {
JAXBContext context = newInstance(Autoruns.class);
unmarshaller = context.createUnmarshaller();
} catch (JAXBException ex) {
throw new LoaderException("Could not create unmarshaller.", ex);
}
try {
return (Autoruns) unmarshaller.unmarshal(file);
} catch (JAXBException ex) {
if (!attemptRecovery) {
throw new LoaderException(ex.getMessage(), ex);
}
}
exceptions.clear();
Autoruns autoruns = new Autoruns();
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
try {
XMLEventReader eventReader =
inputFactory.createXMLEventReader(new FileInputStream(file));
while (eventReader.hasNext()) {
XMLEvent event = eventReader.peek();
if (event.isStartElement()) {
StartElement start = event.asStartElement();
if (start.getName().getLocalPart().equals("item")) {
// note the try should allow processing of elements
// after this item in the event it is malformed
try {
JAXBElement<Autoruns.Item> jax_b =
unmarshaller.unmarshal(eventReader,
Autoruns.Item.class);
autoruns.getItem().add(jax_b.getValue());
} catch (JAXBException ex) {
exceptions.add(ex);
}
}
}
eventReader.next();
}
} catch (XMLStreamException | FileNotFoundException ex) {
exceptions.add(ex);
}
return autoruns;
}
public static Autoruns load(Path path) throws JAXBException {
return load(path.toFile());
}
public static Autoruns load(File file) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(Autoruns.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
return (Autoruns) unmarshaller.unmarshal(file);
}
public static class LoaderException extends Exception {
public LoaderException(String message) {
super(message);
}
public LoaderException(String message, Throwable cause) {
super(message, cause);
}
}
}