目前,我'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 回答
那个"XML"比无效更糟糕 - 它不是很好;见 Well Formed vs Valid XML .
对违法行为可预测性的非正式评估无济于事 . 该文本数据不是XML . 没有符合要求的XML工具或库可以帮助您处理它 .
选项,最首选:
让提供商解决问题 . Demand well-formed XML. (从技术上讲,格式良好的XML是多余的,但可能对强调有用 . )
使用 tolerant markup parser 在解析为XML之前清除问题:
Standalone: xmlstarlet具有强大的恢复和修复功能信用:RomanPerekhrest
Standalone and C: HTML Tidy也适用于XML .
Python: Beautiful Soup是基于Python的 . 请参阅Differences between parsers部分中的注释 . 有关处理Python中格式不正确的标记的更多建议,另请参阅answers to this question . 有关如何使用
codecs.EncodedFile()
清除非法字符的信息,请参阅this answer .Java: JSoup专注于HTML . FilterInputStream可用于preprocessing cleanup .
.NET:
可以禁用
XmlReaderSettings.CheckCharacters以解决非法的XML字符问题 .
@jdweng reports XmlReader.ReadToFollowing()有时可以用于work-around XML syntactical issues,但请注意下面#3中的规则破坏警告 .
据说
Microsoft.Language.Xml.XMLParser是“容错的” .
PHP: 见DOMDocument::$recover和libxml_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 ,使用正则表达式替换
&
匹配:credit:blhsin,demo请注意,上述正则表达式不会考虑注释或CDATA部分 .
标准的XML解析器永远不会接受无效的XML设计 .
您唯一的选择是在解析之前预先处理输入以删除“可预测的无效”内容,或将其包装在CDATA中 .
IMO这些案例应该通过使用JSoup来解决 .
以下是这个具体案例的一个不太真实的答案,但找到this on the web(感谢Coderwall上的inuyasha82) . 在处理格式错误的XML时,这个代码位确实激发了我另一个类似的问题,所以我在这里分享它 .
请不要编辑下面的内容,就像在原始网站上一样 .
XML格式要求在文档中声明的唯一根元素有效 . 例如,有效的xml是:
但是如果你有一个像这样的文件:
这将被视为格式错误的XML,因此许多xml解析器只会抛出一个抱怨没有根元素的异常 . 等等 .
在此示例中,有一个解决方案可以解决该问题,并成功解析上面的格式错误的xml .
基本上我们要做的是以编程方式添加根元素 .
首先,您必须打开包含“格式错误”的xml(即文件)的资源:
然后打开一个FileInputStream:
如果我们尝试在此时使用任何XML库解析此流,我们将引发格式错误的文档Exception .
现在我们创建一个包含三个元素的InputStream对象列表:
包含字符串的ByteIputStream元素:“”我们的FileInputStream带字符串的ByteInputStream:“”所以代码是:
现在使用SequenceInputStream,我们为上面创建的List创建一个容器:
现在我们可以在cntr上使用任何XML Parser库,它将被解析而没有任何问题 . (用Stax库检查);
接受的答案是很好的建议,并包含非常有用的链接 .
我想补充一点这可以使用SGML(HTML和XML的ISO标准化超集)修复未完成和/或DTD无效的XML . 在你的情况下,有效的是将伪造的
THIS-IS-PART-OF-DESCRIPTION
元素声明为SGML空元素,然后使用eg .osx
程序(OpenSP / OpenJade SGML包的一部分)将其转换为XML . 例如,如果您将以下内容提供给osx
它将输出格式良好的XML,以便使用您选择的XML工具进行进一步处理 .
但请注意,您的示例代码段还有另一个问题,即以字母
xml
或XML
或Xml
等开头的元素名称在XML中保留,并且不会被符合XML的解析器接受 .