在Ruby中处理XML和XSLT以及XPath的简单教程
什么是 xml ?
xml 指可扩展标记语言(extensible markup language)。
可扩展标记语言,标准通用标记语言的子集,一种用于标记电子文件使其具有结构性的标记语言。
它可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。 它非常适合万维网传输,提供统一的方法来描述和交换独立于应用程序或供应商的结构化数据。
xml解析器结构和api
xml的解析器主要有dom和sax两种。
- sax解析器是基于事件处理的,需要从头到尾把xml文档扫描一遍,在扫描的过程中,每次遇到一个语法结构时,就会调用这个特定语法结构的事件处理程序,向应用程序发送一个事件。
- dom是文档对象模型解析,构建文档的分层语法结构,在内存中建立dom树,dom树的节点以对象的形式来标识,文档解析文成以后,文档的整个dom树都会放在内存中。
ruby 中解析及创建 xml
ruby中对xml的文档的解析可以使用这个库rexml库。
rexml库是ruby的一个xml工具包,是使用纯ruby语言编写的,遵守xml1.0规范。
在ruby1.8版本及其以后,ruby标准库中将包含rexml。
rexml库的路径是: rexml/document
所有的方法和类都被封装到一个rexml模块内。
rexml解析器比其他的解析器有以下优点:
- 100% 由 ruby 编写。
- 可适用于 sax 和 dom 解析器。
- 它是轻量级的,不到2000行代码。
- 很容易理解的方法和类。
- 基于 sax2 api 和完整的 xpath 支持。
- 使用 ruby 安装,而无需单独安装。
以下为实例的 xml 代码,保存为movies.xml:
<collection shelf="new arrivals"> <movie title="enemy behind"> <type>war, thriller</type> <format>dvd</format> <year>2003</year> <rating>pg</rating> <stars>10</stars> <description>talk about a us-japan war</description> </movie> <movie title="transformers"> <type>anime, science fiction</type> <format>dvd</format> <year>1989</year> <rating>r</rating> <stars>8</stars> <description>a schientific fiction</description> </movie> <movie title="trigun"> <type>anime, action</type> <format>dvd</format> <episodes>4</episodes> <rating>pg</rating> <stars>10</stars> <description>vash the stampede!</description> </movie> <movie title="ishtar"> <type>comedy</type> <format>vhs</format> <rating>pg</rating> <stars>2</stars> <description>viewable boredom</description> </movie> </collection>
dom 解析器
让我们先来解析 xml 数据,首先我们先引入 rexml/document 库,通常我们可以将 rexml 在*的命名空间中引入:
#!/usr/bin/ruby -w require 'rexml/document' include rexml xmlfile = file.new("movies.xml") xmldoc = document.new(xmlfile) # 获取 root 元素 root = xmldoc.root puts "root element : " + root.attributes["shelf"] # 以下将输出电影标题 xmldoc.elements.each("collection/movie"){ |e| puts "movie title : " + e.attributes["title"] } # 以下将输出所有电影类型 xmldoc.elements.each("collection/movie/type") { |e| puts "movie type : " + e.text } # 以下将输出所有电影描述 xmldoc.elements.each("collection/movie/description") { |e| puts "movie description : " + e.text }
以上实例输出结果为:
root element : new arrivals movie title : enemy behind movie title : transformers movie title : trigun movie title : ishtar movie type : war, thriller movie type : anime, science fiction movie type : anime, action movie type : comedy movie description : talk about a us-japan war movie description : a schientific fiction movie description : vash the stampede! movie description : viewable boredom sax-like parsing:
sax 解析器
处理相同的数据文件:movies.xml,不建议sax的解析为一个小文件,以下是个简单的实例:
#!/usr/bin/ruby -w require 'rexml/document' require 'rexml/streamlistener' include rexml class mylistener include rexml::streamlistener def tag_start(*args) puts "tag_start: #{args.map {|x| x.inspect}.join(', ')}" end def text(data) return if data =~ /^\w*$/ # whitespace only abbrev = data[0..40] + (data.length > 40 ? "..." : "") puts " text : #{abbrev.inspect}" end end list = mylistener.new xmlfile = file.new("movies.xml") document.parse_stream(xmlfile, list)
以上输出结果为:
tag_start: "collection", {"shelf"=>"new arrivals"} tag_start: "movie", {"title"=>"enemy behind"} tag_start: "type", {} text : "war, thriller" tag_start: "format", {} tag_start: "year", {} tag_start: "rating", {} tag_start: "stars", {} tag_start: "description", {} text : "talk about a us-japan war" tag_start: "movie", {"title"=>"transformers"} tag_start: "type", {} text : "anime, science fiction" tag_start: "format", {} tag_start: "year", {} tag_start: "rating", {} tag_start: "stars", {} tag_start: "description", {} text : "a schientific fiction" tag_start: "movie", {"title"=>"trigun"} tag_start: "type", {} text : "anime, action" tag_start: "format", {} tag_start: "episodes", {} tag_start: "rating", {} tag_start: "stars", {} tag_start: "description", {} text : "vash the stampede!" tag_start: "movie", {"title"=>"ishtar"} tag_start: "type", {} tag_start: "format", {} tag_start: "rating", {} tag_start: "stars", {} tag_start: "description", {} text : "viewable boredom"
xpath 和 ruby
我们可以使用xpath来查看xml ,xpath 是一门在 xml 文档中查找信息的语言(查看:xpath 教程)。
xpath即为xml路径语言,它是一种用来确定xml(标准通用标记语言的子集)文档中某部分位置的语言。xpath基于xml的树状结构,提供在数据结构树中找寻节点的能力。
ruby 通过 rexml 的 xpath 类支持 xpath,它是基于树的分析(文档对象模型)。
#!/usr/bin/ruby -w require 'rexml/document' include rexml xmlfile = file.new("movies.xml") xmldoc = document.new(xmlfile) # 第一个电影的信息 movie = xpath.first(xmldoc, "//movie") p movie # 打印所有电影类型 xpath.each(xmldoc, "//type") { |e| puts e.text } # 获取所有电影格式的类型,返回数组 names = xpath.match(xmldoc, "//format").map {|x| x.text } p names
以上实例输出结果为:
<movie title='enemy behind'> ... </> war, thriller anime, science fiction anime, action comedy ["dvd", "dvd", "dvd", "vhs"]
xslt 和 ruby
ruby 中有两个 xslt 解析器,以下给出简要描述:
ruby-sablotron
这个解析器是由正义masayoshi takahash编写和维护。这主要是为linux操作系统编写的,需要以下库:
- sablot
- iconv
- expat
你可以在 ruby-sablotron 找到这些库。
xslt4r
xslt4r 由 michael neumann 编写。 xslt4r 用于简单的命令行交互,可以被第三方应用程序用来转换xml文档。
xslt4r需要xmlscan操作,包含了 xslt4r 归档,它是一个100%的ruby的模块。这些模块可以使用标准的ruby安装方法(即ruby install.rb)进行安装。
xslt4r 语法格式如下:
ruby xslt.rb stylesheet.xsl document.xml [arguments]
如果您想在应用程序中使用xslt4r,您可以引入xslt及输入你所需要的参数。实例如下:
require "xslt" stylesheet = file.readlines("stylesheet.xsl").to_s xml_doc = file.readlines("document.xml").to_s arguments = { 'image_dir' => '/....' } sheet = xslt::stylesheet.new( stylesheet, arguments ) # output to stdout sheet.apply( xml_doc ) # output to 'str' str = "" sheet.output = [ str ] sheet.apply( xml_doc )
上一篇: 用Ruby实现一个单元测试框架的教程
下一篇: 深入理解Ruby中的block概念