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上找到此模块。
    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 )