您的位置:首页 > 其它

序列化 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++ 编程指南
DOMWriter
Supported 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








回页首
Xerces-C++ 所支持的输出流

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();

如果您打算接收以 UTF-16 之外的其它方式编码的字符串,可以使用
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();

此处假定与解析器集成在一起的转码器支持您所指定的底层编码。Xerces-C++ 本身支持 ASCII、UTF-8、UTF-16(大/小尾数法,Big/Small Endian)、UCS4(大/小尾数法,Big/Small Endian)、EBCDIC 代码页 IBM037 和 IBM1140、ISO-8859-1(又名 Latin1)以及 Windows-1252。如果您希望支持更多编码(譬如 Shift-JIS 或 Big5),那么您可能会希望使用 XML4C,它将 Xerces-C++ 解析器与 IBM 的 International Components for Unicode(ICU)集成在一起,将所支持的不同编码扩展到 100 多种。

但是,
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

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;

如果该文件尚不存在,则自动创建它。您可以选择在进行任何 I/O 之前刷新(flush)该文件的内容,以确保可以将所有内容写出。

结束语

现在,您应该很好地理解了如何将 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++ 积极的参与者。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐