Ruby Ruby-XML,XSLT和XPath
-
什么是XML?
可扩展标记语言(XML)是一种类似于HTML或SGML的标记语言。万维网联盟建议这样做,并且可以作为开放标准使用。XML是一种可移植的开放源语言,它使程序员能够开发可由其他应用程序读取的应用程序,而无需考虑操作系统和/或开发语言。XML对跟踪少量到中等数量的数据而无需基于SQL的主干非常有用。 -
XML解析器体系结构和API
XML解析器有两种不同的风格-- 类似于SAX的(Stream接口) - 在这里您注册感兴趣事件的回调,然后让解析器继续处理文档。当您的文档很大或有内存限制时,此功能非常有用,它会在从磁盘读取文件时解析文件,并且整个文件永远不会存储在内存中。
- 类DOM(对象树接口) - 这是万维网联盟的建议,其中,将整个文件读入内存并以分层(基于树)的形式存储,以表示XML文档的所有功能。
当处理大文件时,SAX显然无法像DOM一样快地处理信息。另一方面,仅使用DOM确实可以杀死您的资源,尤其是在许多小文件上使用时。SAX是只读的,而DOM允许更改XML文件。由于这两个不同的API实际上相互补充,因此没有理由不能在大型项目中同时使用它们。 -
使用Ruby解析和创建XML
操纵XML的最常见方法是使用Sean Russell的REXML库。自2002年以来,REXML已成为标准Ruby发行版的一部分。REXML是符合XML 1.0标准的纯Ruby XML处理器。它是一个非验证处理器,通过了所有OASIS非验证一致性测试。与其他可用的解析器相比,REXML解析器具有以下优点-- 它是用Ruby 100%编写的。
- 它可以用于SAX和DOM解析。
- 它是轻量级的,少于2000行代码。
- 方法和类确实很容易理解。
- 基于SAX2的API和完整的XPath支持。
- 随Ruby安装一起提供,不需要单独安装。
对于我们所有的XML代码示例,让我们使用一个简单的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库;为了方便起见,通常我们会做一个include REXML导入顶级名称空间。require 'rexml/document' include REXML xmlfile = File.new("movies.xml") xmldoc = Document.new(xmlfile) # Now get the root element root = xmldoc.root puts "Root element : " + root.attributes["shelf"] # This will output all the movie titles. xmldoc.elements.each("collection/movie"){ |e| puts "Movie Title : " + e.attributes["title"] } # This will output all the movie types. xmldoc.elements.each("collection/movie/type") { |e| puts "Movie Type : " + e.text } # This will output all the movie description. 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的解析
为了以面向流的方式处理相同的数据movie.xml文件,我们将定义一个侦听器类,该类的方法将成为解析器中回调的目标。注 – 不建议对小文件使用类似SAX的解析,这仅是一个演示示例。-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
查看XML的另一种方法是XPath。这是一种伪语言,描述了如何在XML文档中定位特定元素和属性,并将该文档视为逻辑顺序树。REXML通过XPath类具有XPath支持。如上所见,它假定基于树的解析(文档对象模型)。require 'rexml/document' include REXML xmlfile = File.new("movies.xml") xmldoc = Document.new(xmlfile) # Info for the first movie found movie = XPath.first(xmldoc, "//movie") p movie # Print out all the movie types XPath.each(xmldoc, "//type") { |e| puts e.text } # Get an array of all of the movie formats. 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该解析器由高桥正敏编写和维护。这主要是为Linux OS编写的,并且需要以下库-- Sablot
- Iconv
- Expat
您可以在Ruby-Sablotron上找到此模块。XSLT4RXSLT4R由Michael Neumann编写,可以在RAA的“库”部分的XML下找到。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 )