📜  Ruby-XML,XSLT和XPath教程

📅  最后修改于: 2020-10-16 06:03:21             🧑  作者: Mango


什么是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文件作为输入-


   
      War, Thriller
      DVD
      2003
      PG
      10
      Talk about a US-Japan war
   
   
      Anime, Science Fiction
      DVD
      1989
      R
      8
      A schientific fiction
   
   
      Anime, Action
      DVD
      4
      PG
      10
      Vash the Stampede!
   
   
      Comedy
      VHS
      PG
      2
      Viewable boredom
   

类似于DOM的解析

首先让我们以树的形式解析XML数据。我们首先需要rexml / document库;为了方便起见,通常我们会做一个include REXML导入顶级名称空间。

#!/usr/bin/ruby -w

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的解析,这仅是一个演示示例。

#!/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

查看XML的另一种方法是XPath。这是一种伪语言,描述了如何在XML文档中定位特定元素和属性,并将该文档视为逻辑顺序树。

REXML通过XPath类具有XPath支持。如上所见,它假定基于树的解析(文档对象模型)。

#!/usr/bin/ruby -w

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

这将产生以下结果-

 ... >
War, Thriller
Anime, Science Fiction
Anime, Action
Comedy
["DVD", "DVD", "DVD", "VHS"]

XSLT和Ruby

Ruby可以使用两个XSLT解析器。这里给出了每个的简短描述。

Ruby-Sablotron

该解析器由高桥正敏编写和维护。这主要是为Linux OS编写的,并且需要以下库-

  • Sablot
  • 艾康
  • 外籍人士

您可以在Ruby-Sablotron上找到此模块。

XSLT4R

XSLT4R由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 )

进一步阅读