以下代码用于解析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
答案 0 :(得分:4)
我可以使用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
未被清除。解析第二个表情符号字符时,它仍包含旧内容,因此字符会附加两次。
如果你尝试使用包含三个或更多表情符号的属性值,你会清楚地看到它们是如何积累的。
答案 1 :(得分:1)
一些更新:此问题已在Java 9的早期访问发行版本中修复(版本9-ea + 103-2016-01-27-183833.javare.4341.nc)。它仍然存在于Java 8的最新版本(build 1.8.0_72-b15)中。出于某种原因,Oracle因为针对此问题针对Java 6/7/8的服务请求而关闭了由于我的服务请求而打开的错误(因为不可重现)。我想让他们重新打开它。
这是针对openjdk打开的完全相同的问题,他们在openjdk 9中修复了它: https://bugs.openjdk.java.net/browse/JDK-8062362