XML支持新的UTF-8,如表情符号

时间:2017-01-13 13:53:57

标签: java xml sax

我们有一个使用XML与服务器通信的移动客户端。当我们需要发送一些最近的UTF-8表情时,我遇到了一个问题,这些表情很容易在新手机上使用。例如:。

现在,我的Android应用程序没有编码和发送它的问题,但在服务器端,事情往往更加爆炸。

如果我们尝试使用上面的任何一个表情发送消息,我们会得到一个巨大的堆栈跟踪,以及相关部分:

javax.xml.transform.TransformerException: org.xml.sax.SAXException: Invalid UTF-16 surrogate detected: d83d d83d ?
java.io.IOException: Invalid UTF-16 surrogate detected: d83d d83d ?
        at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(Unknown Source)
        at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(Unknown Source)

如果我们试图解析它:

2017-01-13 14:00:22,717 - com.zylinc.core.gatekeeper.stripes.DoBean - WARN - Could not handle request
org.xml.sax.SAXParseException; lineNumber: 3; columnNumber: 93; Character reference "&#
        at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
        at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
        at com.zylinc.core.gatekeeper.stripes.DoBean.parseRequest(DoBean.java:127)
        at com.zylinc.core.gatekeeper.stripes.DoBean.execute(DoBean.java:56)
        at com.zylinc.core.gatekeeper.Dispatcher.onRequest(Dispatcher.java:107)
        at com.zylinc.core.gatekeeper.io.UntrustedSocketListener.handleRequest(UntrustedSocketListener.java:16)
        at com.zylinc.core.gatekeeper.io.SocketListener$MessageHandler.run(SocketListener.java:228)
        at java.lang.Thread.run(Unknown Source)

在这种情况下,XML是:

<?xml version="1.0" encoding="UTF-8"?><action>
<set>
<absence requestid="0" from="2017 01 13 13 00 11" to="2017 01 13 22 59 11" subject="&#55357;&#56846;" user_id="CN=???????? ????????????,OU=TestUsers,OU=ZyUsers,DC=Zylinc,DC=com"/>
</set>
</action>

现在,这在输出JSON时似乎工作得很好,但是移动客户端使用JSON并不是我们可以在一夜之间完成的事情。我猜它会破坏,因为与java版本相比,使用的字符太新了,但确保较新的表情不会破坏消息传递会很好。

解析XML的代码非常简单:

SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
XMLReader xmlReader = parser.getXMLReader();
xmlReader.setContentHandler(handler);
StringReader reader = new StringReader(xml);
xmlReader.parse(new InputSource(reader));

编辑:

创建XML就像这样:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
mDoc = builder.newDocument();
mRoot = mDoc.createElement("action");
mDoc.appendChild(mRoot);

TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer trans = transFactory.newTransformer();
trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
trans.setOutputProperty(OutputKeys.INDENT, "yes");
trans.setOutputProperty(OutputKeys.VERSION, "1.1");

StringWriter sw = new StringWriter();
StreamResult result = new StreamResult(sw);
DOMSource source = new DOMSource(mDoc);
trans.transform(source, result);

return sw.toString();

添加文字的地方很简单:

xml.setAttribute(SUBJECT, obj.getSubject());

我是否必须指定一些编码或其他?

1 个答案:

答案 0 :(得分:5)

您对这些进行了错误的编码。

如果您使用的是XML字符引用表示法&#NNNNN;,那么N必须是Unicode代码点,而不是分割为代理项对的Unicode代码点。例如,&#x1f60e;。在你的例子中,你有&#55357;&#56846;这是不合法的,因为55357和56846不是代码点,它们是代理对的两半。

如果您直接代表字符,我不确定您正在做什么,但错误消息“检测到无效的UTF-16代理:d83d d83d”表明您正在做错了。

您的问题标题(“UTF-8喜欢表情符号”)表明您对Unicode和UTF-8感到困惑。 Unicode将表情符号映射到整数代码点,例如第一个是十六进制1f60e或十进制128526. UTF-8是将Unicode编码为字节或八位字节流的一种可能方式,它可以将每个Unicode代码点编码为一到四个字节的序列。

UTF-16是另一种编码,它将大多数Unicode代码点表示为16位,但使用一对16位值的xffff则称为代理对。代替对不用于UTF-8。尝试将UTF-16中的Unicode代码点编码为代理对,然后以UTF-8独立编码该代理对的每一半是错误的。但我怀疑这是你在做什么。