在Java中剥离无效的XML字符

在Java中剥离无效的XML字符

Stripping Invalid XML characters in Java

我有一个XML文件,它是数据库的输出。 我正在使用Java SAX解析器来解析XML并以其他格式输出它。 XML包含一些无效字符,并且解析器抛出诸如"无效Unicode字符(0x5)"之类的错误

除了逐行预处理文件并替换它们之外,是否有一种很好的方法可以去除所有这些字符? 到目前为止,我遇到了3个不同的无效字符(0x5、0x6和0x7)。 这是一个约4gb的数据库转储,我们将对其进行大量处理,因此每次我们要进行新的转储以运行预处理器时,都不得不等待额外的30分钟,这会很痛苦, 这不是我第一次遇到这个问题。


我使用Xalan org.apache.xml.utils.XMLChar类:

1
2
3
4
5
6
7
8
9
10
11
public static String stripInvalidXmlCharacters(String input) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < input.length(); i++) {
        char c = input.charAt(i);
        if (XMLChar.isValid(c)) {
            sb.append(c);
        }
    }

    return sb.toString();
}

我没有亲自使用它,但是Atlassian开发了一种命令行XML清理程序,它可以满足您的需求(它主要是为JIRA而设计的,但XML是XML):

Download atlassian-xml-cleaner-0.1.jar

Open a DOS console or shell, and locate the XML or ZIP backup file on your computer, here assumed to be called data.xml

Run:
java -jar atlassian-xml-cleaner-0.1.jar data.xml > data-clean.xml

This will write a copy of data.xml to data-clean.xml, with invalid characters removed.


我使用了以下正则表达式,该正则表达式似乎可以对JDK6正常工作:

1
2
3
Pattern INVALID_XML_CHARS = Pattern.compile("[^\\\\u0009\\\\u000A\\\\u000D\\\\u0020-\\\\uD7FF\\\\uE000-\\\\uFFFD\\uD800\\uDC00-\\uDBFF\\uDFFF]");
...
INVALID_XML_CHARS.matcher(stringToCleanup).replaceAll("");

在JDK7中,可能对于不在BMP之外的最后一个范围使用符号\\x{10000}-\\x{10FFFF}代替了不那么容易理解的\\uD800\\uDC00-\\uDBFF\\uDFFF符号。


将澳大利亚出口关税的内容解析为XML文档时,我遇到类似的问题。我无法使用此处建议的解决方案,例如:
-使用从命令行调用的外部工具(罐子)。
-要求澳大利亚海关清理源文件。

目前解决此问题的唯一方法是逐个字符地遍历源文件的整个内容,并测试每个字符是否不属于0x00到0x1F的ASCII范围。可以做到,但是我想知道是否有更好的方法将Java方法用于String类型。

编辑
我发现了一种可能对其他人有用的解决方案:使用Java方法String#ReplaceAll替换或删除XML文档中的任何不需要的字符。

示例代码(为避免混乱,我删除了一些必要的语句):

1
2
3
BufferedReader reader = null;
...
String line = reader.readLine().replaceAll("[\\\\x00-\\\\x1F]","");

在此示例中,我删除(即替换为空字符串)不可打印的字符(范围包括0x00至0x1F)。您可以在方法#replaceAll()中更改第二个参数,以将字符替换为应用程序所需的字符串。


您的问题与XML无关:它与字符编码有关。最终的结果是,每个字符串(无论是XML还是其他形式)都由字节组成,并且您不知道这些字节代表什么字符,除非您被告知编码该字符串的字符是什么。例如,如果供应商告诉您它是UTF-8,而实际上是其他东西,那么您肯定会遇到问题。在最好的情况下,一切正常,但是某些字节会转换为"错误"字符。在最坏的情况下,您会遇到类似遇到的错误。

实际上,您的问题甚至更糟:您的字符串包含不代表任何字符编码中的字符的字节序列。没有文本处理工具,更不用说XML解析器了。这需要字节级清除。


是否有可能您的无效字符仅出现在值中,而不是标记本身,即XML在概念上符合架构,但值未得到正确清理?如果是这样,如何覆盖InputStream来创建CleansingInputStream,以将无效字符替换为XML等效字符?


推荐阅读