目前,我正在研究一项涉及解析我们从其他产品收到的XML的功能。我决定对一些实际的客户数据进行一些测试,看起来其他产品允许来自用户的输入被认为是无效的。无论如何,我仍然需要尝试找出解析它的方法。我们正在使用javax.xml.parsers.DocumentBuilder
,我收到的输入错误如下所示。
<xml>
...
<description>Example:Description:<THIS-IS-PART-OF-DESCRIPTION></description>
...
</xml>
正如您所知,描述中的内容似乎是无效标记(<THIS-IS-PART-OF-DESCRIPTION>
)。现在,已知此描述标记是叶标记,并且不应在其中包含任何嵌套标记。无论如何,这仍然是一个问题,并在DocumentBuilder.parse(...)
我知道这是无效的XML,但它可以预测无效。有关解析此类输入的方法的任何想法吗?
答案 0 :(得分:18)
“XML”比无效更糟糕 - 它的形式不正确;请参阅 Well Formed vs Valid XML 。
对违法行为可预测性的非正式评估无济于事。该文本数据不是XML。没有符合条件的XML工具或库可以帮助您处理它。
使用容错标记解析器在解析为XML之前清除问题:
独立: xmlstarlet具有强大的恢复和修复功能 credit:RomanPerekhrest
xmlstarlet fo -o -R -H -D bad.xml 2>/dev/null
独立和C: HTML Tidy也适用于XML。
codecs.EncodedFile()
清除非法字符。FilterInputStream
可用于preprocessing cleanup。XmlReaderSettings.ConformanceLevel
可以设置为
ConformanceLevel.Fragment
以便XmlReader
可以阅读缺少根元素的XML Well-Formed Parsed Entities。XmlReader.ReadToFollowing()
有时可以
习惯于work-around XML syntactical issues,但请注意
在#3下面的规则破坏警告。Microsoft.Language.Xml.XMLParser
被称为“容错”。使用文本编辑器或手动处理数据作为文本 以编程方式使用字符/字符串函数。这样做 以编程方式可以从棘手到不可能 似乎是什么 可预测通常不是 - 规则中断很少受规则约束。
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}", ' ')
inputStr.replace(/[^\x09\x0A\x0D\x20-\xFF\x85\xA0-\uD7FF\uE000-\uFDCF\uFDE0-\uFFFD]/gm, '')
对于&符号,请使用正则表达式将匹配项替换为&
: credit:blhsin,demo
&(?!(?:#\d+|#x[0-9a-f]+|\w+);)
请注意,上述正则表达式不会采用注释或CDATA 部分考虑在内。
答案 1 :(得分:1)
标准XML解析器永远不会接受无效的XML设计。
您唯一的选择是在解析之前预先处理输入以删除“可预测的无效”内容,或将其包装在CDATA中。
答案 2 :(得分:1)
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库);
答案 3 :(得分:1)
接受的答案是好建议,并包含非常有用的链接。
我想补充一点,使用SGML(ISO标准化的HTML超集)可以修复many other未正确和/或DTD无效的XML案例和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工具进行进一步处理。
但请注意,您的示例代码段存在另一个问题,即以字母xml
或XML
或Xml
等开头的元素名称以XML格式保留,并赢得了#39 ;是否符合XML解析器。