我们有一个使用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="��" 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());
我是否必须指定某些编码或其他编码?
你对这些编码不正确。
如果使用 XML 字符引用表示法,&#NNNNN;
,则 N 必须是 Unicode 代码点,而不是拆分为代理项对的 Unicode 代码点。例如,😎
.在您的示例中,您有不合法��
,因为 55357 和 56846 不是代码点,它们是代理项对的两半。
在您直接表示字符的情况下,我不确定您在做什么,但错误消息"检测到无效的 UTF-16 代理项:d83d d83d"非常清楚地表明您做错了。
您问题的标题("UTF-8 like smileys")表明您在 Unicode 和 UTF-8 之间感到困惑。Unicode 将笑脸映射到整数代码点,例如第一个是十六进制 1f60e 或十进制128526。UTF-8 是将 Unicode 编码为字节流或八位字节的一种可能方法,它可以将每个 Unicode 代码点编码为一到四个字节的序列。
UTF-16 是另一种编码,它将大多数 Unicode 代码点表示为 16 位,但 xffff 以上的代码点使用一对 16 位值,称为代理项对。代理项对在 UTF-8 中不使用。尝试将 UTF-16 中的 Unicode 代码点编码为代理项对,然后用 UTF-8 独立编码此代理项对的每一部分是完全错误的。但我不知何故怀疑这就是你在做什么。