首页 文章

如何解析无效(错误/不良格式)的XML?

提问于
浏览
12

目前,我'm working on a feature that involves parsing XML that we receive from another product. I decided to run some tests against some actual customer data, and it looks like the other product is allowing input from users that should be considered invalid. Anyways, I still have to try and figure out a way to parse it. We'正在使用 javax.xml.parsers.DocumentBuilder ,我收到的输入错误如下所示 .

<xml>
  ...
  <description>Example:Description:<THIS-IS-PART-OF-DESCRIPTION></description>
  ...
</xml>

正如您所知,描述中的内容似乎是无效标记( <THIS-IS-PART-OF-DESCRIPTION> ) . 现在,已知此描述标记是叶标记,并且不应在其中包含任何嵌套标记 . 无论如何,这仍然是一个问题,并在 DocumentBuilder.parse(...) 上产生异常

我知道这是无效的XML,但它可以预测无效 . 有关解析此类输入的方法的任何想法?

4 回答

  • 1

    那个"XML"比无效更糟糕 - 它不是很好;见 Well Formed vs Valid XML .

    对违法行为可预测性的非正式评估无济于事 . 该文本数据不是XML . 没有符合要求的XML工具或库可以帮助您处理它 .

    选项,最首选:

    • 让提供商解决问题 . Demand well-formed XML. (从技术上讲,格式良好的XML是多余的,但可能对强调有用 . )

    • 使用 tolerant markup parser 在解析为XML之前清除问题:

    • Standalone: xmlstarlet具有强大的恢复和修复功能信用:RomanPerekhrest

    xmlstarlet fo -o -R -H -D bad.xml 2>/dev/null
    

    可以禁用

    据说

    • Microsoft.Language.Xml.XMLParser是“容错的” .

    • PHP:DOMDocument::$recoverlibxml_use_internal_errors(true) . 看到好的例子here .

    • Ruby: Nokogiri支持“Gentle Well-Formedness” .

    • R: 有关R中的容错标记解析,请参阅htmlTreeParse()

    • Process the data as text 使用文本编辑器手动或使用字符/字符串函数以编程方式 . 以编程方式执行此操作的范围可以从 tricky to impossible 开始,因为看起来可预测的通常不是 rule breaking is rarely bound by rules .

    • 对于 invalid character errors ,使用正则表达式删除/替换无效字符:

    • PHP: preg_replace('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', ' ', $s);

    • Ruby: string.tr("^\u{0009}\u{000a}\u{000d}\u{0020}-\u{D7FF}\u{E000}-\u{FFFD}", ' ')

    • JavaScript: inputStr.replace(/[^\x09\x0A\x0D\x20-\xFF\x85\xA0-\uD7FF\uE000-\uFDCF\uFDE0-\uFFFD]/gm, '')

    • 对于 ampersands ,使用正则表达式替换 &amp; 匹配:credit:blhsin,demo

    &(?!(?:#\d+|#x[0-9a-f]+|\w+);)
    

    请注意,上述正则表达式不会考虑注释或CDATA部分 .

  • 1

    标准的XML解析器永远不会接受无效的XML设计 .

    您唯一的选择是在解析之前预先处理输入以删除“可预测的无效”内容,或将其包装在CDATA中 .

  • 14

    IMO这些案例应该通过使用JSoup来解决 .

    以下是这个具体案例的一个不太真实的答案,但找到this on the web(感谢Coderwall上的inuyasha82) . 在处理格式错误的XML时,这个代码位确实激发了我另一个类似的问题,所以我在这里分享它 .

    请不要编辑下面的内容,就像在原始网站上一样 .

    XML格式要求在文档中声明的唯一根元素有效 . 例如,有效的xml是:

    <root>
         <element>...</element>
         <element>...</element>
    </root>
    

    但是如果你有一个像这样的文件:

    <element>...</element>
    <element>...</element>
    <element>...</element>
    <element>...</element>
    

    这将被视为格式错误的XML,因此许多xml解析器只会抛出一个抱怨没有根元素的异常 . 等等 .

    在此示例中,有一个解决方案可以解决该问题,并成功解析上面的格式错误的xml .

    基本上我们要做的是以编程方式添加根元素 .

    首先,您必须打开包含“格式错误”的xml(即文件)的资源:

    File file = new File(pathtofile);
    

    然后打开一个FileInputStream:

    FileInputStream fis = new FileInputStream(file);
    

    如果我们尝试在此时使用任何XML库解析此流,我们将引发格式错误的文档Exception .

    现在我们创建一个包含三个元素的InputStream对象列表:

    包含字符串的ByteIputStream元素:“”我们的FileInputStream带字符串的ByteInputStream:“”所以代码是:

    List<InputStream> streams = 
        Arrays.asList(
            new ByteArrayInputStream("<root>".getBytes()),
        fis,
        new ByteArrayInputStream("</root>".getBytes()));
    

    现在使用SequenceInputStream,我们为上面创建的List创建一个容器:

    InputStream cntr = 
    new SequenceInputStream(Collections.enumeration(str));
    

    现在我们可以在cntr上使用任何XML Parser库,它将被解析而没有任何问题 . (用Stax库检查);

  • 1

    接受的答案是很好的建议,并包含非常有用的链接 .

    我想补充一点这可以使用SGML(HTML和XML的ISO标准化超集)修复未完成和/或DTD无效的XML . 在你的情况下,有效的是将伪造的 THIS-IS-PART-OF-DESCRIPTION 元素声明为SGML空元素,然后使用eg . osx 程序(OpenSP / OpenJade SGML包的一部分)将其转换为XML . 例如,如果您将以下内容提供给 osx

    <!DOCTYPE xml [
      <!ELEMENT xml - - ANY>
      <!ELEMENT description - - ANY>
      <!ELEMENT THIS-IS-PART-OF-DESCRIPTION -  - EMPTY>
    ]>
    <xml>
      <description>blah blah
        <THIS-IS-PART-OF-DESCRIPTION>
      </description>
    </xml>
    

    它将输出格式良好的XML,以便使用您选择的XML工具进行进一步处理 .

    但请注意,您的示例代码段还有另一个问题,即以字母 xmlXMLXml 等开头的元素名称在XML中保留,并且不会被符合XML的解析器接受 .

相关问题