4.3.4 响应消息对象转XML

公众账号服务器接收并处理完用户发送的消息后,需要返回特定的XML结构对消息进行响应。为了方便在程序中以对象的方式操作消息,我们已经在4.2.3节中将各种类型的响应消息封装成了Java对象。现在要解决的问题是如何将响应消息对象转换成XML字符串,这就需要用到4.3.2节中介绍的XStream类库,实现代码如下:

  1. /**
  2. * 扩展xstream使其支持CDATA
  3. */
  4. private static XStream xstream = new XStream(new XppDriver() {
  5. public HierarchicalStreamWriter createWriter(Writer out) {
  6. return new PrettyPrintWriter(out) {
  7. // 对所有XML节点的转换都增加CDATA标记
  8. boolean cdata = true;
  9.  
  10. @SuppressWarnings("unchecked")
  11. public void startNode(String name, Class clazz) {
  12. super.startNode(name, clazz);
  13. }
  14.  
  15. protected void writeText(QuickWriter writer, String text) {
  16. if (cdata) {
  17. writer.write("<![CDATA[");
  18. writer.write(text);
  19. writer.write("]]>");
  20. } else {
  21. writer.write(text);
  22. }
  23. }
  24. };
  25. }
  26. });
  27.  
  28. /**
  29. * 文本消息对象转换成XML
  30. *
  31. * @param textMessage 文本消息对象
  32. * @return xml
  33. */
  34. public static String messageToXml(TextMessage textMessage) {
  35. xstream.alias("xml", textMessage.getClass());
  36. return xstream.toXML(textMessage);
  37. }
  38.  
  39. /**
  40. * 图片消息对象转换成XML
  41. *
  42. * @param imageMessage 图片消息对象
  43. * @return xml
  44. */
  45. public static String messageToXml(ImageMessage imageMessage) {
  46. xstream.alias("xml", imageMessage.getClass());
  47. return xstream.toXML(imageMessage);
  48. }
  49.  
  50. /**
  51. * 语音消息对象转换成XML
  52. *
  53. * @param voiceMessage 语音消息对象
  54. * @return xml
  55. */
  56. public static String messageToXml(VoiceMessage voiceMessage) {
  57. xstream.alias("xml", voiceMessage.getClass());
  58. return xstream.toXML(voiceMessage);
  59. }
  60.  
  61. /**
  62. * 视频消息对象转换成XML
  63. *
  64. * @param videoMessage 视频消息对象
  65. * @return xml
  66. */
  67. public static String messageToXml(VideoMessage videoMessage) {
  68. xstream.alias("xml", videoMessage.getClass());
  69. return xstream.toXML(videoMessage);
  70. }
  71.  
  72. /**
  73. * 音乐消息对象转换成XML
  74. *
  75. * @param musicMessage 音乐消息对象
  76. * @return xml
  77. */
  78. public static String messageToXml(MusicMessage musicMessage) {
  79. xstream.alias("xml", musicMessage.getClass());
  80. return xstream.toXML(musicMessage);
  81. }
  82.  
  83. /**
  84. * 图文消息对象转换成XML
  85. *
  86. * @param newsMessage 图文消息对象
  87. * @return xml
  88. */
  89. public static String messageToXml(NewsMessage newsMessage) {
  90. xstream.alias("xml", newsMessage.getClass());
  91. xstream.alias("item", new Article().getClass());
  92. return xstream.toXML(newsMessage);
  93. }

由于XStream本身不支持CDATA,上面的代码首先对XStream做了扩展,使其支持在生成XML各元素值时添加CDATA标记。接着,通过方法重载定义了6个messageToXml()方法,用于将响应消息对象转换成XML。


说明 XML解析器通常会解析XML文档中的所有文本。当某个XML元素被解析时,其标签之间的文本也会被解析,所以,在XML元素中,“<”和“&”是非法的,因为“<”会被解析器解释为新元素的开始,而“&”会被解析器解释为字符实体的开始,因此不能这样写:。

那么,对于XML标签内的文本的确需要包含“<”或“&”时该如何处理?这就要用到转义字符或CDATA,本书采用的是后者。CDATA指的是不应由XML解析器进行解析的文本数据(Unparsed Character Data),CDATA标记由“<![CDATA[”开始,由“]]>”结束,标记内的所有文本都会被解析器忽略。因此,上面那段XML的正确写法应该是:。