具有表情符号字符的 java xml 解析器

标签 java xml parsing emoji

以下代码用于解析一个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

最佳答案

我可以使用 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);
                    }

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

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

关于具有表情符号字符的 java xml 解析器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31867818/

相关文章:

java - 编译时强制 Jaxb 优先选择联合成员类型

java - 在扩展另一个对象的同时实现 RealmModel 接口(interface)

java - Gradle 和 Lwjgl 3 Native

xml - 用于选择多个标签的 XPath

ios - 解析 Xcode 8 和 swift 3 CompletianHandler 错误

java - 在Java中加载和显示HTML+CSS

Python:使用 sympy.sympify 对数学函数执行安全 eval()

java - 如何将网站变成Android应用程序

Java 正则表达式转大写

java - 将大型 xml 文件加载到 Snowflake 中并按标签压平