首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >解析破损XML

解析破损XML
EN

Stack Overflow用户
提问于 2016-09-28 09:58:00
回答 1查看 337关注 0票数 1

我试图解析一些第三方XML,其中包含了一些我认为是“非法”的特性。

  • 多根元素
  • “匿名”关闭标记
  • 载有
  • 不匹配的开始和结束标记

示例

代码语言:javascript
复制
<foo>
  <toto>123</>  <!-- == "anonymous" close tag -->
  <tata>
     <titi>456</>
  </>     <!-- == "anonymous" close tag-->
</foo>
<bar>   <!-- == multiple root elements -->
</bar>

这是我从未听说过的XML的某种变体吗?到目前为止,我发现的所有东西,包括良好的格式和错误处理,都表明这不是XML。

标记名区分大小写;开始标记和结束标记必须完全匹配。 一个根元素包含所有其他元素。

我只是想知道用Java解析这个问题的最简单方法,而不必求助于regex。我正在考虑初始解析来纠正XML,这样我就可以使用XPath或其他标准机制。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-12-23 06:13:18

我发现修复这个问题的唯一方法是对整个输入进行标记化,并逐块重新构建它,过滤出问题,正确地关闭标记等等。

此外,我还通过用新元素根包装整个内容,即<root>${content}</root>,修正了多个根标记问题。

代码语言:javascript
复制
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;

    }

}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39744118

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档