2016-09-28 103 views
1

我试图解析其中一些有一些我认为是“非法”的特色解析破损的XML

  • 多个根元素
  • “匿名”关闭标签第三方XML
  • 不匹配的开始和结束标签

- 包含注释
<foo> 
    <toto>123</> <!-- == "anonymous" close tag --> 
    <tata> 
    <titi>456</> 
    </>  <!-- == "anonymous" close tag--> 
</foo> 
<bar> <!-- == multiple root elements --> 
</bar> 

这是XML的一些变体,我还没有听说过?目前为止我发现的所有东西包括Well-formedness and error-handling都表明这不是XML。

标签名称区分大小写;开始标签和结束标签必须完全匹配。

单根元素包含所有其他元素。

我只是想知道什么最简单的方法来解析这个在Java中,而不必诉诸于正则表达式。我正在考虑初始分析来纠正XML,以便我可以使用XPath或其他标准机制。

+0

乍一看,我会说,你将需要使用解析器来处理这个问题一般。最简单的解决方案可能是回到源代码并要求更清晰的XML数据。 –

+0

我的建议,不要使用正则表达式。坏消息是,你可能需要根据你拥有的文档来找出并构建你自己的解析器,除非这个奇怪的习惯用法可用。 – Mena

+0

匿名关闭标签是一个问题 - 你确定每个开始标签都只有一个标签吗?否则,没有办法解析这个。 – RealSkeptic

回答

0

我发现解决这个问题的唯一办法是标记化整个输入,并通过一块重建它一块过滤掉的问题,通过包裹整个结束标签正确等

另外我固定所述多个根标签问题内容与新的元素根,即<root>${content}</root>

public class BrokenXmlParser { 

    public String parse(InputStream resource) throws IOException { 

     StringBuilder builder = new StringBuilder(); 
     try (BufferedReader reader = new BufferedReader(new InputStreamReader(resource))) { 
      String line = null; 
      while ((line = reader.readLine()) != null) { 
       builder.append(line + "\n"); 
      } 
     } 
     List<String> tokens = tokenize(builder.toString()); 
     return correct(tokens); 
    } 

    private String correct(List<String> tokens) { 
     StringBuilder reassemble = new StringBuilder(); 
     reassemble.append("<root>"); 
     Deque<String> tagNameStack = new ArrayDeque<>(); 
     boolean skip = false; 
     for (int i = 0; i < tokens.size(); i++) { 
      String token = tokens.get(i); 
      if ("<".equals(token)) { 
       tagNameStack.push(tokens.get(i + 1)); 
      } 
      if ("<?".equals(token) || "<!".equals(token)) { 
       // skip comments 
       skip = true; 
      } else if ("<".equals(token)) { 
       skip = false; 
      } 
      if ("</>".equals(token)) { 
       reassemble.append("</" + tagNameStack.pop() + ">"); 
      } else if ("</".equals(token)) { 
       // sometimes tags are incorrectly closed 
       reassemble.append("</" + tagNameStack.pop() + ">"); 
       i = i + 2; 
      } else if (!skip) { 
       reassemble.append(token); 
      } 
     } 
     reassemble.append("</root>"); 
     return reassemble.toString(); 
    } 

    private List<String> tokenize(String input) { 
     List<String> tokens = new ArrayList<>(); 
     Pattern tag = Pattern.compile("(</>|<!|<\\?|\\?>|</|<|>|\\s+|[^<> ]+)"); 
     Matcher matcher = tag.matcher(input); 
     while (matcher.find()) { 
      tokens.add(matcher.group(1)); 
     } 
     return tokens; 

    } 

}