我试图解析一些第三方XML,其中包含了一些我认为是“非法”的特性。
示例
<foo>
<toto>123</> <!-- == "anonymous" close tag -->
<tata>
<titi>456</>
</> <!-- == "anonymous" close tag-->
</foo>
<bar> <!-- == multiple root elements -->
</bar>这是我从未听说过的XML的某种变体吗?到目前为止,我发现的所有东西,包括良好的格式和错误处理,都表明这不是XML。
标记名区分大小写;开始标记和结束标记必须完全匹配。 一个根元素包含所有其他元素。
我只是想知道用Java解析这个问题的最简单方法,而不必求助于regex。我正在考虑初始解析来纠正XML,这样我就可以使用XPath或其他标准机制。
发布于 2016-12-23 06:13:18
我发现修复这个问题的唯一方法是对整个输入进行标记化,并逐块重新构建它,过滤出问题,正确地关闭标记等等。
此外,我还通过用新元素根包装整个内容,即<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;
}
}https://stackoverflow.com/questions/39744118
复制相似问题