【问题标题】:An invalid XML character (Unicode: 0xc) was found发现无效的 XML 字符 (Unicode: 0xc)
【发布时间】:2011-08-10 04:42:57
【问题描述】:

使用 Java DOM 解析器解析 XML 文件会导致:

[Fatal Error] os__flag_8c.xml:103:135: An invalid XML character (Unicode: 0xc) was found in the element content of the document.
org.xml.sax.SAXParseException: An invalid XML character (Unicode: 0xc) was found in the element content of the document.
    at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(Unknown Source)
    at javax.xml.parsers.DocumentBuilder.parse(Unknown Source)

【问题讨论】:

    标签: java xml dom xml-parsing


    【解决方案1】:

    XML 文档中有一些字符是不允许使用的,即使您将数据封装在 CDATA 块中也是如此。

    如果您生成了文档,则需要对其进行实体编码或将其剥离。如果你有一个错误的文档,你应该在尝试解析它之前去掉这些字符。

    在此线程中查看 dolmens 的答案:Invalid Characters in XML

    他在哪里链接到这篇文章:http://www.w3.org/TR/xml/#charsets

    基本上,0x20 以下的所有字符都是不允许的,除了 0x9 (TAB)、0xA (CR?)、0xD (LF?)

    【讨论】:

    • +1 - 基本上,OP的问题是他试图解析的XML文件无效。
    • 实体编码不起作用; XML 文本中根本不允许该值
    • 在 UTF-8 上,不允许使用的字符的完整列表是这 5 个十六进制间隔:0..8B..CE..1FD800..DFFFFFFE..FFFF
    【解决方案2】:

    字符 0x0C 在 XML 1.0 中无效,但应该是 valid character in XML 1.1。因此,除非 xml 文件在序言中将版本指定为 1.1,否则它就是无效的,您应该向该文件的生产者投诉。

    【讨论】:

      【解决方案3】:

      我遇到了类似的问题,即 XML 包含控制字符。查看代码后,我发现一个已弃用的类 StringBufferInputStream 用于读取字符串内容。

      http://docs.oracle.com/javase/7/docs/api/java/io/StringBufferInputStream.html

      This class does not properly convert characters into bytes. As of JDK 1.1, the preferred way to create a stream from a string is via the StringReader class.
      

      我将其更改为 ByteArrayInputStream 并且效果很好。

      【讨论】:

        【解决方案4】:

        每当无效的 xml 字符出现在 xml 中时,就会出现这样的错误。当您在记事本++ 中打开它时,它看起来像 VT、SOH、FF,这些都是无效的 xml 字符。我正在使用 xml 版本 1.0,并且在通过模式将文本数据输入数据库之前验证文本数据

        Pattern p = Pattern.compile("[^\u0009\u000A\u000D\u0020-\uD7FF\uE000-\uFFFD\u10000-\u10FFF]+"); 
        retunContent = p.matcher(retunContent).replaceAll("");
        

        保证xml中不会输入无效的特殊字符

        【讨论】:

        • 您提供的模式是正确的,但无法按原样编译。你需要一些逃避。正确的是Pattern.compile("[^\\u0009\\u000A\\u000D\\u0020-\\uD7FF\\uE000-\\uFFFD\\u10000-\\u10FFF]+")
        【解决方案5】:
        public String stripNonValidXMLCharacters(String in) {
            StringBuffer out = new StringBuffer(); // Used to hold the output.
            char current; // Used to reference the current character.
        
            if (in == null || ("".equals(in))) return ""; // vacancy test.
            for (int i = 0; i < in.length(); i++) {
                current = in.charAt(i); // NOTE: No IndexOutOfBoundsException caught here; it should not happen.
                if ((current == 0x9) ||
                    (current == 0xA) ||
                    (current == 0xD) ||
                    ((current >= 0x20) && (current <= 0xD7FF)) ||
                    ((current >= 0xE000) && (current <= 0xFFFD)) ||
                    ((current >= 0x10000) && (current <= 0x10FFFF)))
                    out.append(current);
            }
            return out.toString();
        }    
        

        【讨论】:

        • 如果你能编写一个基于正则表达式的解决方案,它既健壮又快速
        • 正则表达式通常较慢,上面的代码会更快,因为它只做这件事
        • 现在不要使用StringBuffer,而是使用StringBuilder,因为它更快(不需要对象监视器/未同步)。
        【解决方案6】:

        您可以使用自定义 FilterReader 类过滤所有“无效”字符:

        public class InvalidXmlCharacterFilter extends FilterReader {
        
            protected InvalidXmlCharacterFilter(Reader in) {
                super(in);
            }
        
            @Override
            public int read(char[] cbuf, int off, int len) throws IOException {
                int read = super.read(cbuf, off, len);
                if (read == -1) return read;
        
                for (int i = off; i < off + read; i++) {
                    if (!XMLChar.isValid(cbuf[i])) cbuf[i] = '?';
                }
                return read;
            }
        }
        

        然后像这样运行它:

        InputStream fileStream = new FileInputStream(xmlFile);
        Reader reader = new BufferedReader(new InputStreamReader(fileStream, charset));
        InvalidXmlCharacterFilter filter = new InvalidXmlCharacterFilter(reader);
        InputSource is = new InputSource(filter);
        xmlReader.parse(is);
        

        【讨论】:

        • 嗨瓦迪姆,你的想法很棒。 XMLChar 的来源是什么?
        • 我在 com.sun.org.apache.xml.internal.utils.XMLChar 上找到了 XMLChar(在 Java 1.8 中)
        【解决方案7】:

        对于将字节数组读入字符串并尝试使用 JAXB 转换为对象的人,您可以通过从字节数组创建字符串来添加“iso-8859-1”编码,如下所示:

        String JAXBallowedString= new String(byte[] input, "iso-8859-1");

        这会将冲突的字节替换为 JAXB 可以处理的单字节编码。显然这个解决方案只是解析xml。

        【讨论】:

          【解决方案8】:

          所有这些答案似乎都假设用户正在生成错误的 XML,而不是从 gSOAP 接收它,这应该更清楚!

          【讨论】:

          • 再一次,可能是内存访问问题导致内容损坏。
          【解决方案9】:

          今天,我遇到了类似的错误:

          Servlet.service() for servlet [remoting] in context with path [/***] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: buildDocument failed.] with root cause org.xml.sax.SAXParseException; lineNumber: 19; columnNumber: 91; An invalid XML character (Unicode: 0xc) was found in the value of attribute "text" and element is "label".


          在我第一次遇到错误后,我手动重新输入了整行,因此没有办法让特殊字符潜入,并且 Notepad++ 没有显示任何不可打印的字符(黑色白色),但我一遍又一遍地遇到同样的错误。

          当我查看我所做的与我的前辈不同的事情时,结果发现它在结束 /> 之前是一个额外的空间(正如我听说的那样,建议用于较旧的解析器,但它不应该使任何无论如何,根据 XML 标准):

          &lt;label text="this label's text" layout="cell 0 0, align left" /&gt;

          当我删除空间时:

          &lt;label text="this label's text" layout="cell 0 0, align left"/&gt;

          一切正常。


          所以这绝对是一个误导性的错误信息。

          【讨论】:

            【解决方案10】:

            在 UTF-8 上,对于 XML 1.0,这些范围内的所有代码都是不允许的:

            • 0..8
            • B..C
            • E..1F
            • D800..DFFF
            • FFFE..FFFF

            可以删除的正则表达式是:

            text.replaceAll('[\\x{0}-\\x{8}]|[\\x{B}-\\x{C}]|[\\x{E}-\\x{1F}]|[\\x{D800}-\\x{DFFF}]|[\\x{FFFE}-\\x{FFFF}]', "")
            

            注意:如果您使用的是 XML 1.1,您还需要删除这些间隔:

            • 7F..84
            • 86..9F

            参考:

            【讨论】:

              猜你喜欢
              • 2011-09-05
              • 2013-09-10
              • 1970-01-01
              • 2012-12-02
              • 2017-04-23
              • 1970-01-01
              • 1970-01-01
              • 2021-03-26
              相关资源
              最近更新 更多