【问题标题】:java xml parser with emoji character带有表情符号的java xml解析器
【发布时间】:2015-10-30 07:31:20
【问题描述】:

以下代码用于解析 xml 文件。我注意到表情符号字符没有被正确解析。在示例中,输入末尾有一个表情符号(http://www.iemoji.com/view/emoji/693/people/revolving-hearts),该字符在输出中加倍。这是一个已知的错误吗?

import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class XmlTest {

    public static void main(String[] args) {            
        DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
        domFactory.setValidating(false);
        File file = new File("c:\\temp\\emoji.xml");

        try {
            DocumentBuilder builder = domFactory.newDocumentBuilder();
            Document doc = builder.parse(file);

            NodeList nodes = doc.getElementsByTagName("entry");
            Node node = nodes.item(0);
            NamedNodeMap map = ((Element)node).getAttributes();

            for (int i=0; i<map.getLength(); i++) {
                Node n = map.item(i);
                System.out.println();
                System.out.println(n.getNodeValue());

                char[] chars = n.getNodeValue().toCharArray();

                for (int j=0; j<chars.length; j++) {
                    System.out.print(chars[j] + ", " + (int)chars[j] + "  ");                   
                }
            }

        } catch (Exception e) {e.printStackTrace(); }
    }
}

这里是输入的 emoji.xml:

<Attributes>
  <Map>
    <entry key="name" value="????test????"/>
  </Map>
</Attributes>

和输出:

name
n, 110  a, 97  m, 109  e, 101  
????test????????
?, 55357  ?, 56478  t, 116  e, 101  s, 115  t, 116  ?, 55357  ?, 56478  ?, 55357  ?, 56478

【问题讨论】:

    标签: java xml parsing emoji


    【解决方案1】:

    我可以使用 JDK 1.7 重现该问题。

    问题的原因似乎是 JDK 附带的 XML 解析器中的一个 错误 (在这种情况下,它是 Xerces,位于 rt.jar 中的包 com.sun.org.apache.xerces.internal.* 中)

    表情符号字符不在 Unicode BMP 中,因此表示为两个字符(高代理和低代理)。当解析器遇到这些代理时,它会以特殊方式处理它们,并在转换为补充字符时检查它们是否是有效的 XML 字符。

    错误代码位于以下代码部分的XMLScanner.scanAttributeValue

               } else if (c != -1 && XMLChar.isHighSurrogate(c)) {
                    if (scanSurrogates(fStringBuffer3)) {
                        stringBuffer.append(fStringBuffer3);
                        if (entityDepth == fEntityDepth && fNeedNonNormalizedValue) {
                            fStringBuffer2.append(fStringBuffer3);
                        }
    

    表情符号字符的两个字符被解析为缓冲区变量fStringBuffer3,然后附加到属性值的缓冲区中。现在的问题是fStringBuffer3 没有被清除。在解析第二个表情符号字符时,它仍然包含旧内容,因此字符被附加了两次。

    如果您尝试使用包含三个或更多表情符号的属性值,您会清楚地看到它们是如何累积的。

    【讨论】:

    • 有趣的是,我在第一篇文章中编写了测试代码,并将其传递给了我们的一个客户。我针对这个问题打开了针对 Oracle JVM 的服务请求。 Oracle SR 号:3-11255842301 Oracle 缺陷号:21694036
    【解决方案2】:

    一些更新:此问题已在 Java 9 的早期访问版本(内部版本 9-ea+103-2016-01-27-183833.javare.4341.nc)中得到修复。它仍然存在于 Java 8 的最新版本(版本 1.8.0_72-b15)中。出于某种原因,Oracle 关闭了由于我针对 Java 6/7/8 对此问题的服务请求而打开的错误(因为不可重现)。我正试图让他们重新打开它。

    这是完全相同的问题,针对 openjdk 打开,他们在 openjdk 9 中修复了它: https://bugs.openjdk.java.net/browse/JDK-8062362

    【讨论】:

    • 显然,这个错误已在 Java 1.8.0_92 中修复:bugs.openjdk.java.net/browse/JDK-8141098 我可以确认 Java 1.8.0_102 不再出现此错误
    • 感谢大家的侦探工作,终于在这方面取得了进展。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-22
    • 2016-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多