Lua中使用DOM读写XML
在Lua神作《PIL》中操作XML的示例是用expat库的,众所周知expat是用类似SAX的接口的,这里介绍一下使用其他的库来实现DOM接口操作XML。
可以使用的库有几个选择,包括ltxml,xerces,rapidxml等等。ltxml使用TinyXML和TinyXPath提供的服务,xerces使用Xerces-C++提供的服务,而rapidxml则是使用RapidXML。这三个库我都有过一段时间的使用,不过都没怎么深入过。总的说来三个库各有特色,呃,其实是它们依赖的C/C++库的特点,ltxml我不是很喜欢,当初用的时候发现不知道为什么,同样一段代码执行多次后,打开并读取XML文档就会出错。于是后来转用xerces,它倒是基本让人满意,不过得附带一个Xerces-C++的DLL,感觉有点不爽,而且Xerces-C++应该说是比较完整的实现了XML的几个接口标准,但xerces只是封装了其中DOM读写的很小一部分接口。而rapidxml胜在运行速度飞快,从RapidXML的项目主页上可以看到一个简单的横向评测结果。xerces和rapidxml的Lua接口非常相似,除了几个节点类型常量的名称和载入的表的名称不同外,其他的读写接口名称和签名几乎一模一样,它们的源代码可以在它们的项目主页上通过svn下载得到,但需要用户自己编译,当然也可以下载安装LuaPack,LuaPack提供已经编译好的xerces和rapidxml文件,但要注意的是由于使用VC2010进行编译,只能在Windows XP SP3或更高版本的Windows系统上运行。
下面以rapidxml为例,简单演示一下如何操作XML文档。
新建一个XML文档,并保存:
require "rapidxml"
local doc = rapidxml.parse( "
local root = doc:root()
for i = 1, 10 do
local new_child = root:append( string.format( "test_node_%d", i ) ) -- create new child node
new_child:set_attr( "index", tostring( i * 10 ) ) -- append new attribute named index with value i *10
new_child:set_text( tostring( i * 20 ) ) -- set node text
end
doc:save( "C:\\testxml\\testdata.xml" , true )
打开刚才创建并保存的XML文件,并读取:
require "rapidxml"
local doc = rapidxml.open( "C:\\testxml\\testdata.xml" )
local root = doc:root()
local child_nodes = root:children()
for k, child_node in pairs( child_nodes ) do
if child_node:type() == rapidxml.node_element then
if child_node:exists_attr( "index" ) then
print( child_node:name(), child_node:attribute( "index" ) ) -- 打印该节点的名称和index属性值
end
print( child_node:text() ) -- 打印该节点的文本内容
end
end
比较方便的是,rapidxml把子节点集合用Lua table表示,所以可以方便地使用pairs等Lua的设施来进行操作。xerces的使用方法与上面的代码类似。