2017-01-13 13 views
0

我們有一個使用XML與服務器通信的移動客戶端。當我們需要發送一些更新的UTF-8表情符號時,我遇到了一個問題,這些表情符號在新手機上很容易找到。例如: 。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()); 

我必須指定一些編碼或其他?

+0

您可能別無選擇,只能對含有emojis的元素進行base64編碼。即使ASCII控制代碼也是非法的XML文本,例如  Stavr00

回答

3

您對這些錯誤進行了編碼。

如果您使用XML字符引用符號&#NNNNN;,那麼N必須是Unicode代碼點,而不是Unicode代碼點分成代理對。例如,&#x1f60e;。在你的例子中,你有&#55357;&#56846;這是不合法的,因爲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中獨立編碼此代理項對的每一半是非常錯誤的。但我懷疑這是你在做什麼。

+0

我已經添加了如何在底部創建XML,我沒有看到任何明顯的東西。 –

+0

您正在將String創建爲StringWriter中的一個字符串,它是一系列Java字符(實際上是UTF-16)。但是您向我們展示的XML聲明它是UTF-8。在某些時候,UTF-16字符必須已經變成UTF-8八位字節,這可能是問題所在。 –