使用jaxb解析无效的xml - 解析器可以更宽松吗?

问题描述:

我一直在使用JAXB,而现在来解析XML看起来大致是这样的:使用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

一个简单的问题有关的问题:你有没有注意到同样的错误重复出现?例如,标签在很多地方都没有关闭? – xwang 2016-07-01 19:36:09

这个答案真的帮了我:

JAXB - unmarshal XML exception

就我而言,我解析从Sysinternals的自动运行工具的结果与XML开关(-x)。要么是因为结果正在写入文件共享中,要么是因为更新版本中的一些错误原因,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); 
     } 
    } 
} 
+0

感谢发帖,3年后嘿嘿:) – samz 2015-04-15 20:10:17

XML的哲学是XML的创建者负责创建格式良好的XML,收件人不负责在到达时修复不良的XML。 XML解析器需要拒绝格式不正确的XML。还有其他一些“整洁”的工具可能会将坏的XML转换为良好的XML,但根据输入中缺陷的性质,这是不可预测的,它们将如何工作。如果您将获得使用XML进行数据交换的好处,则需要格式良好。否则,你可能会使用自己的专有格式。

+0

不幸的是,在现实生活中,并非每个人都坚持这一理念。在我的情况下,发送端尝试发送有效的xml(而不是某种特殊格式),但由于很多原因(主要是它们的错误代码)不成功。我必须以某种方式处理。我试图尽可能地使用内置的高级java工具(jaxb),而无需构建我自己的解析器(进入“低级别”)。任何有用的意见/代码将受到欢迎。 – samz 2012-07-19 06:57:36

+1

是的,现实生活是混乱的。幸运的是,我可以告诉您什么是正确的技术解决方案,并让您解决您无法控制整个系统来实施正确技术解决方案的问题。 – 2012-07-20 10:13:19

+0

我对技术解决方案感兴趣。我已经在使用JAXB,但采用了一种非常基本的方式。我不知道如何实施这个解决方案,也没有在网上找到任何有用的信息。这就是为什么我最终在这里... – samz 2012-07-24 14:19:38