序列化 XML 数据
2007-11-05 11:17
351 查看
序列化 XML 数据
用 XML for C++ 解析器中的 DOMWriter 保存 XML 数据级别: 中级
Tinny Ng (tng@ca.ibm.com), 系统架构业务方案设计师, IBM 多伦多实验室
2003 年 9 月 01 日
IBM 开发人员 Tinny Ng 向您展示了如何将 XML 数据序列化成具有不同编码的 DOMString。您还会看到一些示例,它们演示如何使用 XML4C/Xerces-C++ 中的 MemBufFormatTarget、StdOutFormatTarget 和 LocalFileFormatTarget 输出流。
Xerces-C++ 是一种用 C++ 编写的 XML 解析器,它由开放源码 Apache XML 项目分发。去年年初起,Xerces-C++ 根据 W3C Document Object Model(DOM)Level 3 Core Specification 和 W3C Document Object Model(DOM)Level 3 Load and Save Specification(请参阅 参考资料)的规定,添加了 W3C 文档对象模型(Document Object Model,DOM)Level 3 子集的实验性实现。
DOM Level 3 Load and Save Specification 定义了一组接口,允许用户将来自于不同输入源的 XML 内容装入和保存到不同的输出流。本文以示例向您展示了如何以这种方式保存 XML 数据。用户可以使这些输出数据流入字符串、内部缓冲区、标准输出或文件。在下列章节中,我将向您展示如何将 XML 数据序列化成具有不同编码的
DOMString,以及如何使用 Xerces-C++ 中的
MemBufFormatTarget、
StdOutFormatTarget和
LocalFileFormatTarget。
注:IBM XML for C++(XML4C)将 Xerces-C++ 和 International Components for Unicode(ICU)集成到一起,以提供对 100 多种不同编码的支持。在本文档中,我将用 Xerces-C++ 来表示用于 C++ 的 XML 解析器。但是,除非另有指定,否则所描述的行为将同时适用于 XML4C 和 Xerces C++。
序列化 XML 数据
DOMBuilder类提供了用于解析 XML 文档和构建相应 DOM 文档树的 API;而
DOMWriter类提供了将 DOM 文档序列化(写)到 XML 文档的 API。要序列化 XML 数据,首先使用
DOMBuilder将 XML 数据装入到 DOM 树,然后使用
DOMWriter写出 DOM 树。例如:
清单 1. 序列化 XML 数据
// DOMImplementationLS contains factory methods for creating objects // that implement the DOMBuilder and the DOMWriter interfaces static const XMLCh gLS[] = { chLatin_L, chLatin_S, chNull }; DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(gLS); // construct the DOMBuilder DOMBuilder* myParser = ((DOMImplementationLS*)impl)-> createDOMBuilder(DOMImplementationLS::MODE_SYNCHRONOUS, 0); // parse the XML data, assume it is saved in a local file // called "theXMLFile.xml" // the DOMBuilder will parse the data and return it as a DOM tree DOMNode* aDOMNode = myParser->parseURI("theXMLFile.xml"); // construct the DOMWriter DOMWriter* myWriter = ((DOMImplementationLS*)impl)->createDOMWriter(); // optionally, set some DOMWriter features // set the format-pretty-print feature if (myWriter->canSetFeature(XMLUni::fgDOMWRTFormatPrettyPrint, true)) myWriter->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint, true); // set the byte-order-mark feature if (myWriter->canSetFeature(XMLUni::fgDOMWRTBOM, true)) myWriter->setFeature(XMLUni::fgDOMWRTBOM, true); // serialize the DOMNode to a UTF-16 string XMLCh* theXMLString_Unicode = myWriter->writeToString(*aDOMNode); // release the memory XMLString::release(&theXMLString_Unicode); myWriter->release(); myParser->release(); |
DOMBuilder和
DOMWriter都是使用
DOMImplementationLS中的工厂方法构造的。在使用完它们后,必需显式地释放它们,以释放任何相关的资源。此外,从
writeToString返回的字符串归调用程序所拥有,调用程序负责释放所分配的内存。
您也可以选择设置一些控制
DOMWriter行为的功能。Xerces-C++ 实现了 W3C DOM Level 3 Load and Save Specification 中规定的许多
DOMWriter功能。可以在 Xerces-C++ 编程指南
DOMWriterSupported Features(请参阅 参考资料)中找到这些功能的完整列表。其中有两个功能值得着重提一下:
格式美化— 这个功能通过添加换行回车符和缩进空格来对输出进行格式化,以生成美化的、可读性良好的格式。因为 W3C DOM Level 3 Load and Save Specification 中没有规定确切的转换格式,所以解析器有它自己的解释。在 Xerces-C++ 2.2(或 XML4C 5.1)之前的发行版中,解析器只对序言和后记进行美化。它不会触及根元素中的内容。但从 Xerces-C++ 2.2(或 XML4C 5.1)开始,启用这个功能也会引起对根元素中内容的格式化。
字节顺序标记(byte-order-mark)— 这是 Xerces-C++ 2.2(或 XML4C 5.1)中添加的非标准扩展,用来支持在所生成的 XML 流中写入字节顺序标记(Byte-Order-Mark,BOM)。当且仅当
DOMDocumentNode是为序列化而生成的时候,BOM 才被写入所生成的 XML 流的开头部分,并且输出编码是下列之一:
UTF-16
UTF-16LE
UTF-16BE
UCS-4
UCS-4LE
UCS-4BE
![]() ![]() |
![]()
|
DOMWriter提供了一个 API,用于将 DOM 节点写入各种类型的输出流中。Xerces-C++ 支持四种输出流类型:
DOMString
MemBufFormatTarget
StdOutFormatTarget
LocalFileFormatTarget
DOMString
用户可以使用
DOMWriter的
writeToString方法将
DOMNode序列化成
DOMString(即 Xerces-C++ 中的
XMLCh*)。这个方法完全忽略所有可用的编码信息,所返回的字符串 总是用 UTF-16 编码的。正如先前提到的,从
writeToString返回的字符串归调用程序所拥有,调用程序负责释放所有已分配的内存。例如:
清单 2. 将 DOMNode 序列化成 UTF-16 字符串
// construct the DOMWriter DOMWriter* myWriter = ((DOMImplementationLS*)impl)->createDOMWriter(); // serialize a DOMNode to a UTF-16 string XMLCh* theXMLString_Unicode = myWriter->writeToString(*aDOMNode); // release the memory XMLString::release(&theXMLString_Unicode); myWriter->release(); |
XMLTranscoder手工转换字符串的编码。使用
XMLPlatformUtils::fgTransService-> makeNewTranscoderFor构造用于特定编码的
XMLTranscoder,然后调用
transcodeTo将 UTF-16 字符串转码成您指定的编码。例如:
清单 3. 将 DOMNode 序列化成 Big5 字符串
// construct the DOMWriter DOMWriter* myWriter = ((DOMImplementationLS*)impl)->createDOMWriter(); // serialize a DOMNode to a UTF-16 string XMLCh* theXMLString_Unicode = myWriter->writeToString(*aDOMNode); // construct a transcoder in Big5 XMLTransService::Codes resCode; XMLTranscoder* aBig5Transcoder = XMLPlatformUtils::fgTransService-> makeNewTranscoderFor("Big5", resCode, 16*1024, XMLPlatformUtils::fgMemoryManager); // transcode the string into Big5 unsigned int charsEaten; char resultXMLString_Encoded[16*1024+4]; aBig5Transcoder->transcodeTo(theXMLString_Unicode, XMLString::stringLen(theXMLString_Unicode), (XMLByte*) resultXMLString_Encoded, 16*1024, charsEaten, XMLTranscoder::UnRep_Throw ); // release the memory XMLString::release(&theXMLString_Unicode); delete aBig5Transcoder; myWriter->release(); |
但是,
XMLTranscoder不会更改输入字符串的 XML 声明中所存储的编码信息,该字符串是由
writeToString所生成的。因此这个以手工方式转码的 XML 字符串的编码属性仍然是“UTF-16”而不是“Big5”。如果您对整个
DOMDocumentNode进行序列化,而 XML 声明中包括了编码信息的话,这会引起误解。
在这种情况下,要接收非 UTF-16 编码的字符串,建议您使用
MemBufFormatTarget。
MemBufFormatTarget
MemBufFormatTarget将 XML 数据保存到内部缓冲区。
MemBufFormatTarget在构造时初始化为一个 1023 字节的内存缓冲区,并可根据需要增加。请求时,通过
getRawBuffer()方法返回以空(null)结束的
XMLByte流。如果用户打算使返回的缓冲区与
MemBufFormatTarget的状态无关,他们应该制作自己的返回缓冲区副本。否则,该缓冲区会在破坏
MemBufFormatTarget时被删除,或者在调用
reset()函数时被复位。
所返回的
XMLByte流的编码以如下顺序确定:
使用
DOMWriter中的编码设置
如果该设置为空,那么使用将要写入的 DOM 流的编码属性
如果上述两处都未提供编码名称,则使用缺省编码 UTF-8
DOMWriter将在 XML 声明的编码属性中存储正确的编码信息(它与字符串的实际编码相匹配)。
清单 4 说明了如何接收用 Big-5 编码的 XML 字符串:
清单 4. 使用 MemBufFormatTarget
// construct the DOMWriter DOMWriter* myWriter = ((DOMImplementationLS*)impl)->createDOMWriter(); // construct the MemBufFormatTarget XMLFormatTarget *myFormatTarget = new MemBufFormatTarget(); // set the encoding to be Big5 XMLCh tempStr[100]; XMLString::transcode("Big5", tempStr, 99); myWriter->setEncoding(tempStr); // serialize a DOMNode to an internal memory buffer myWriter->writeNode(myFormatTarget, *aDOMNode); // get the string which is encoded in Big 5 from the MemBufFormatTarget char* theXMLString_Encoded = (char*) ((MemBufFormatTarget*)myFormatTarget)->getRawBuffer(); // release the memory myWriter->release(); delete myFormatTarget; |
DOMWriter将发出致命错误。
除了将 XML 数据序列化到内部缓冲区之外,还有两种其它类型的输出流:
StdOutFormatTarget和
LocalFileFormatTarget。
StdOutFormatTarget
StdOutFormatTarget将 XML 数据保存到标准输出。例如:
清单 5. 使用 StdOutFormatTarget
// construct the DOMWriter DOMWriter* myWriter = ((DOMImplementationLS*)impl)->createDOMWriter(); // construct the StdOutFormatTarget XMLFormatTarget *myFormatTarget = new StdOutFormatTarget(); // serialize a DOMNode to the standard output myWriter->writeNode(myFormatTarget, *aDOMNode); // release the memory myWriter->release(); delete myFormatTarget; |
LocalFileFormatTarget将 XML 数据保存到实际的本地文件。在构造
LocalFileFormatTarget时,用户需要将本地文件名作为参数进行传递。例如:
清单 6. 使用 LocalFileFormatTarget
// construct the DOMWriter DOMWriter* myWriter = ((DOMImplementationLS*)impl)->createDOMWriter(); // construct the LocalFileFormatTarget XMLFormatTarget *myFormatTarget = new LocalFileFormatTarget("myXMLFile.xml"); // serialize a DOMNode to the local file "myXMLFile.xml" myWriter->writeNode(myFormatTarget, *aDOMNode); // optionally, you can flush the buffer to ensure all contents are written myFormatTarget->flush(); // release the memory myWriter->release(); delete myFormatTarget; |
结束语
现在,您应该很好地理解了如何将 XML 数据序列化成具有不同编码的不同类型的输出流。这里重申一下,有关更多详细信息,请参阅 W3C DOM Level 3 Load and Save Specification 以及 Xerces-C++ 中的完整 API 文档。
参考资料
您可以参阅本文在 developerWorks 全球站点上的 英文原文.
请阅读 W3C Document Object Model(DOM)Level 3.0 Core Specification,它是 W3C 定义的规范,允许程序和脚本动态地访问和更新文档的内容、结构和样式。
当您研究本文时,可以查看 W3C DOM Level 3 Load and Save Specification,该规范允许程序和脚本动态地将 XML 文档的内容装入 DOM 文档,并允许将 DOM 文档序列化成 XML 文档。
尝试一下 Xerces-C++,这是一种由 Apache 分发的用于 C++ 的 XML 解析器。
浏览 IBM alphaWorks 网站,您将看到大量 XML 工具,包括 用于 C++ 的 XML 解析器(XML4C)。
研究一下 International Components for Unicode(ICU)库。它们提供了针对各种平台的健壮且功能齐全的 Unicode 服务。XML4C 将 Xerces-C++ 与 ICU 集成到一起以扩展解析器中的编码支持。
请参考 Xerces-C++ 编程指南 DOMWriter Supported Features,以获取
DOMWriter类所支持的所有功能的列表。
请查看 Xerces-C++ 中的完整 API 文档,以全面理解 Xerces-C++ API 的工作原理。
请查看如何使您成为 IBM 认证的 XML 及相关技术开发人员。
关于作者
![]() | ||
![]() | Tinny Ng 是咨询软件开发人员,目前担任 IBM 多伦多实验室的 WebSphere 系统架构(WebSphere System House)的业务方案解决方案设计师。她原先是 XML for C++ 解析器开发团队的领导,并在两年中带领该团队交付了九个 Apache Xerces-C++ 发行版和七个 IBM XML4C 发行版。Tinny 还领导过 C++ XML 解析器的体系结构设计工作,包括在解析器中重新设计 DOM 实现以获取更高的性能,以及定义新的 DOM C++ 绑定,后来 W3C 引用了这个绑定。她是 Apache XML 开放源码项目 Xerces-C++ 积极的参与者。 |
相关文章推荐
- wcf 基础教程 契约 Contract 控制xml输出 数据契约DataContract序列化前身 XmlSerializer xml序列化
- 使用ASP.NET AJAX异步调用Web Service和页面中的类方法(10):服务器端和客户端数据类型的自动转换:以XML方式序列化数据、小结
- Android中使用xml保存数据(xml文件序列化)及使用pull解析xml文件
- 序列化XML的类。包括向SQL传XML数据
- .net2.0中WebService在序列化xml数据Generic字典类型的问题
- Android应用中使用XmlSerializer序列化XML数据的教程
- DateTime数据类型的XML序列化及时区问题
- 反序列化,从XML中取数据
- XML数据序列化和反序列化
- xml 数据可配置序列化 示例
- 处理:SqlServer FOR XML 无法对节点 'NoName' 的数据进行序列化,因为它包含在 XML 中不允许出现的字符(0x0000)。
- unity Dictionary序列化和反序列化及XML本地数据存储
- 序列化对象到Xml文件以及反序列话Xml文件到对象(序列化数据到8个Java原型类型)
- 服务器端和客户端数据类型的自动转换:以XML方式序列化数据
- XML序列化数据对象(二)
- XML序列化数据对象(三)
- unity中三种数据存储方式ScriptableObject,Json,Xml和Dictionary的序列化
- InnerException 消息是“反序列化对象 属于类型 *** 时出现错误。读取 XML 数据时,超出最大字符串内容长度配额 (8192)。(注意细节)
- Andriod开发——数据存储及XML序列化的学习
- Android--序列化XML数据