Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/348.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 解析损坏的XML_Java_Xml - Fatal编程技术网

Java 解析损坏的XML

Java 解析损坏的XML,java,xml,Java,Xml,我试图解析一些第三方XML,它有许多我认为是“非法”的特性 多个根元素 “匿名”关闭标记 包含-- 开始和结束标记不匹配 范例 <foo> <toto>123</> <!-- == "anonymous" close tag --> <tata> <titi>456</> </> <!-- == "anonymous"

我试图解析一些第三方XML,它有许多我认为是“非法”的特性

  • 多个根元素
  • “匿名”关闭标记
  • 包含--
  • 开始和结束标记不匹配
范例

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

123
456
这是我从未听说过的XML的变体吗?到目前为止,我所发现的一切,包括,都表明这不是XML

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

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


我只是想知道在Java中用什么最简单的方法来解析它而不必求助于正则表达式。我正在考虑将初始解析更正为XML,这样我就可以使用XPath或其他标准机制。

我发现解决这一问题的唯一方法是对整个输入进行标记化,然后逐段重新构建,过滤掉问题,正确关闭标记等

此外,我还修复了多个根标记的问题,用新元素root包装整个内容,即
${content}

公共类BrokenXmlParser{
公共字符串分析(InputStream资源)引发IOException{
StringBuilder=新的StringBuilder();
try(BufferedReader=new BufferedReader(new InputStreamReader(资源))){
字符串行=null;
而((line=reader.readLine())!=null){
builder.append(第+行“\n”);
}
}
List tokens=tokenize(builder.toString());
返回正确的(代币);
}
私有字符串正确(列出令牌){
StringBuilder重新组装=新建StringBuilder();
重新组装。追加(“”);
Deque tagNameStack=new ArrayDeque();
布尔跳跃=假;
for(inti=0;i如果(“我发现解决这个问题的唯一方法是将整个输入标记化,然后逐个重建,过滤掉问题,正确地关闭标记等等

此外,我还修复了多个根标记的问题,用新元素root包装整个内容,即
${content}

公共类BrokenXmlParser{
公共字符串分析(InputStream资源)引发IOException{
StringBuilder=新的StringBuilder();
try(BufferedReader=new BufferedReader(new InputStreamReader(资源))){
字符串行=null;
而((line=reader.readLine())!=null){
builder.append(第+行“\n”);
}
}
List tokens=tokenize(builder.toString());
返回正确的(代币);
}
私有字符串正确(列出令牌){
StringBuilder重新组装=新建StringBuilder();
重新组装。追加(“”);
Deque tagNameStack=new ArrayDeque();
布尔跳跃=假;
for(inti=0;i如果(”乍一看,我想说的是,您通常需要使用解析器来处理此问题。最简单的解决方案可能是返回源代码并请求更干净的XML数据。我的建议是,不要使用正则表达式。坏消息是,除非有可用的文档,否则您可能需要找出并构建自己的解析器对于这个奇怪的习惯用法,请注意。匿名关闭标记是一个问题-你确定每个开始标记都有一个吗?否则,就没有办法解析它。@RealDis疑者是的,总是匹配关闭标记,尽管同一文件中的一些标记正确关闭。例如,在1997-8年开发XML期间,有一个建议允许最小化d关闭标记,如….该语法已被Microsoft XML parser的beta版接受,但在1998年批准1.0标准时,他们很快取消了对该语法的支持。SGML中允许使用该语法,因此您可能会发现您可以使用SGML语法分析器来解析此文档。乍一看,您需要使用语法分析器来处理此pro总的来说是一个问题。最简单的解决方案可能是返回源代码并请求更干净的XML数据。我的建议是,不要使用正则表达式。坏消息是,您可能需要根据您拥有的文档找出并构建自己的解析器,除非有一个解析器可用于这种奇怪的习惯用法。匿名关闭标记是一个问题-您确定re对于每个开始标记正好是一个?否则,就没有办法解析它。@realpoint Yes始终匹配关闭标记,尽管同一文件中的某些标记已正确关闭。例如,在1997-8年开发XML期间,有一项建议允许最小化关闭标记,如……该语法已被Microsoft X的测试版接受ML解析器,但在1998年批准1.0标准时,他们很快就取消了对它的支持。它在SGML中是允许的,因此您可能会发现可以使用SGML解析器解析此文档。
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;

    }

}