提问人:jvhashe 提问时间:6/27/2017 最后编辑:kjhughesjvhashe 更新时间:10/12/2022 访问量:35018
如何解析无效(错误/格式不正确)的XML?
How to parse invalid (bad / not well-formed) XML?
问:
目前,我正在开发一个功能,该功能涉及解析我们从另一个产品接收的 XML。我决定对一些实际的客户数据进行一些测试,看起来其他产品允许用户输入应被视为无效的输入。无论如何,我仍然需要尝试找出一种方法来解析它。我们正在使用,我在输入时遇到如下所示的错误。javax.xml.parsers.DocumentBuilder
<xml>
...
<description>Example:Description:<THIS-IS-PART-OF-DESCRIPTION></description>
...
</xml>
正如你所知道的,描述里面有一个似乎是无效的标签()。现在,这个描述标签已知是一个叶子标签,里面不应该有任何嵌套标签。无论如何,这仍然是一个问题,并产生了一个例外<THIS-IS-PART-OF-DESCRIPTION>
DocumentBuilder.parse(...)
我知道这是无效的 XML,但它是可以预见的无效的。关于解析此类输入的方法的任何想法?
答:
根据设计,标准 XML 解析器永远不会接受无效的 XML。
唯一的选择是预处理输入以删除“可预见的无效”内容,或在解析之前将其包装在 CDATA 中。
评论
“XML”比无效更糟糕——它的格式不正确;请参阅格式正确的 XML 与有效的 XML。
对违法行为的可预测性进行非正式评估无济于事。该文本数据不是 XML。没有符合要求的 XML 工具或库可以帮助您处理它。
选项,最理想的第一:
让提供商自行解决问题。要求格式正确的 XML。(从技术上讲,短语“格式正确的 XML”是多余的,但可能有助于强调。
在解析为 XML 之前,使用宽容标记解析器清理问题:
独立:xmlstarlet 具有强大的恢复和修复能力 图片来源:RomanPerekhrest
xmlstarlet fo -o -R -H -D bad.xml 2>/dev/null
Python: Beautiful Soup 是基于 Python 的。请参阅分析器之间的差异部分中的注释。另请参阅此问题的答案以了解更多信息 在 Python 中处理格式不正确的标记的建议, 尤其包括 lxml 的
recover=True
选项。 另请参阅此答案,了解如何使用清理非法字符。codecs.EncodedFile()
Java:TagSoup 和 JSoup 专注于 HTML。
FilterInputStream
可用于预处理清理。。网:
- XmlReaderSettings.CheckCharacters 可以 被禁用以解决非法的 XML 字符问题。
- @jdweng指出,可以将
XmlReaderSettings.ConformanceLevel 设置为 ConformanceLevel.Fragment
,以便XmlReader
可以读取缺少根元素的 XML 格式良好的分析实体。 - @jdweng 还报告说
XmlReader.ReadToFollowing()
有时可以 用于解决 XML 语法问题,但请注意 下面 #3 中的违规警告。 Microsoft.Language.Xml.XMLParser
被称为“容错”的。
去:将
Decoder.Strict
设置为,如本示例中所示,由 @chuckx 设置。false
PHP的:请参阅 DOMDocument::$recover 和 libxml_use_internal_errors(true)。在这里看到很好的例子。
红宝石:Nokogiri 支持“温和的良好形状”。
R:请参阅 htmlTreeParse() 了解 R 中的容错标记解析。
Perl:请参阅 XML::Liberal,一个“解析损坏的 XML 的超级自由 XML 解析器”。
使用文本编辑器手动将数据处理为文本,或者 以编程方式使用字符/字符串函数。这样做 编程范围可以从棘手到不可能,因为 似乎是什么 可预测往往不是——违反规则很少受到规则的约束。
对于无效字符错误,请使用正则表达式删除/替换无效字符:
- PHP的:
preg_replace('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', ' ', $s);
- 红宝石:
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, '')
- PHP的:
对于 & 符号,请使用正则表达式将匹配项替换为: credit: blhsin, demo
&
&(?!(?:#\d+|#x[0-9a-f]+|\w+);)
请注意,上述正则表达式不会接受注释或 CDATA 部分考虑在内。
评论
/&(?!(?:#\d+|#x[0-9a-fA-F]+|\w+);)(?!(?:(?!<!\[CDATA\[|\]\]>).)*\]\]>)(?!(?:(?!<!--|-->).)*-->)/g
xmllint --recover --html --dropdtd --xmlout --format 2>/dev/null file
(在最新版本中)做什么。与 xsltproc 和 xmlstarlet 一样,xmllint 依赖于 libxml2,并且通常与 libxml2 一起分发。注意:在版本 20913 中,列出的选项比 更多。xmlstarlet format -R -H -D 2>/dev/null file
xmllint --help
man xmllint
IMO 这些情况应该使用 JSoup 来解决。
下面是这个特定案例的不是真正的答案,但在网上找到了这个(感谢 Coderwall 上的 inuyasha82)。在处理格式错误的 XML 时,这个代码位确实启发了我另一个类似的问题,所以我在这里分享它。
请不要编辑下面的内容,因为它与原始网站上的内容相同。
XML 格式要求文档中声明的唯一根元素有效。
例如,一个有效的 xml 是:
<root>
<element>...</element>
<element>...</element>
</root>
但是,如果您有以下文档:
<element>...</element>
<element>...</element>
<element>...</element>
<element>...</element>
这将被视为格式错误的 XML,因此许多 xml 解析器只会抛出一个 Exception,抱怨没有根元素。等。
在此示例中,有一个关于如何解决该问题并成功解析上述格式错误的 xml 的解决方案。
基本上,我们要做的是以编程方式添加一个根元素。
因此,首先,您必须打开包含“格式错误”的 xml(即文件)的资源:
File file = new File(pathtofile);
然后打开一个 FileInputStream:
FileInputStream fis = new FileInputStream(file);
如果我们尝试使用任何 XML 库解析此流,我们将引发格式错误的文档 Exception。
现在,我们创建一个包含三个 lements 的 InputStream 对象列表:
- 一个 ByteIputStream 元素,其中包含以下字符串:
<root>
- 我们的 FileInputStream
- 带有以下字符串的 ByteInputStream:
</root>
所以代码是:
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 解析器库,并且它将毫无问题地被解析。(与 Stax 图书馆核对);
接受的答案是很好的建议,并包含非常有用的链接。
我想补充一点,这个以及许多其他格式不正确和/或DTD无效的XML情况可以使用SGML(HTML和XML的ISO标准化超集)进行修复。在你的例子中,有效的方法是将虚假元素声明为SGML空元素,然后使用例如。程序(OpenSP/OpenJade SGML 包的一部分)将其转换为 XML。例如,如果您向THIS-IS-PART-OF-DESCRIPTION
osx
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 工具进行进一步处理。
但是请注意,您的示例代码段存在另一个问题,即以字母或等开头的元素名称保留在 XML 中,并且不会被符合要求的 XML 解析器接受。xml
XML
Xml
评论