2012-07-16 49 views
1

我一直在使用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

回答

2

這個答案真的幫了我:

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

2

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