Ruby XML, XSLT 和 XPath 教程

在 Ruby 中,处理 XML(Extensible Markup Language)XSLT(Extensible Stylesheet Language Transformations)XPath(XML Path Language) 是常见的任务,特别是在需要解析、转换或查询结构化数据的场景。Ruby 提供了多种库(如 Nokogiri)来处理这些技术。本教程将重点讲解如何使用 Ruby 处理 XML、XSLT 和 XPath,涵盖核心概念、安装、基本操作、示例代码及注意事项,力求简洁清晰。


1. 概述

  • XML:一种标记语言,用于存储和传输结构化数据。
  • XPath:一种查询语言,用于在 XML 文档中定位节点或提取数据。
  • XSLT:一种转换语言,用于将 XML 文档转换为其他格式(如 HTML、XML)。
  • Ruby 工具Nokogiri 是最流行的 Ruby 库,支持 XML 解析、XPath 查询和 XSLT 转换。

2. 安装 Nokogiri

Nokogiri 是 Ruby 中处理 XML 和 HTML 的首选库,支持 XPath 和 XSLT。

先决条件

  • 安装开发依赖库:
  • Ubuntu
    bash sudo apt-get install libxml2-dev libxslt1-dev
  • macOS
    bash brew install libxml2 libxslt
  • Windows:通常无需额外安装,gem 会自动处理。

安装 Nokogiri

gem install nokogiri

验证

require 'nokogiri'
puts Nokogiri::VERSION  # 输出:1.15.4(示例版本)

3. XML 解析与操作

Nokogiri 提供了简单的方法来解析和操作 XML 文档。

解析 XML

require 'nokogiri'

# 示例 XML
xml = <<~XML
  <?xml version="1.0" encoding="UTF-8"?>
  <employees>
    <employee id="1">
      <name>Alice</name>
      <age>30</age>
    </employee>
    <employee id="2">
      <name>Bob</name>
      <age>25</age>
    </employee>
  </employees>
XML

# 解析 XML
doc = Nokogiri::XML(xml)
puts doc.to_xml  # 输出格式化的 XML

说明

  • Nokogiri::XML(string):解析 XML 字符串。
  • to_xml:将文档转换回 XML 字符串。

创建 XML

使用 Nokogiri::XML::Builder 创建 XML。

require 'nokogiri'

builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
  xml.employees do
    xml.employee(id: 1) do
      xml.name "Alice"
      xml.age 30
    end
    xml.employee(id: 2) do
      xml.name "Bob"
      xml.age 25
    end
  end
end

puts builder.to_xml

输出

<?xml version="1.0" encoding="UTF-8"?>
<employees>
  <employee id="1">
    <name>Alice</name>
    <age>30</age>
  </employee>
  <employee id="2">
    <name>Bob</name>
    <age>25</age>
  </employee>
</employees>

修改 XML

# 修改节点内容
doc.xpath("//employee[@id='1']/name").first.content = "Alicia"
# 添加新节点
employee = doc.xpath("//employee[@id='2']").first
employee.add_child("<role>Developer</role>")
puts doc.to_xml

输出(部分):

<employee id="1">
  <name>Alicia</name>
  <age>30</age>
</employee>
<employee id="2">
  <name>Bob</name>
  <age>25</age>
  <role>Developer</role>
</employee>

4. XPath 查询

XPath 用于在 XML 文档中定位节点或提取数据。Nokogiri 支持完整的 XPath 语法。

基本 XPath 查询

require 'nokogiri'

xml = <<~XML
  <employees>
    <employee id="1">
      <name>Alice</name>
      <age>30</age>
    </employee>
    <employee id="2">
      <name>Bob</name>
      <age>25</age>
    </employee>
  </employees>
XML

doc = Nokogiri::XML(xml)

# 查询所有员工姓名
names = doc.xpath("//employee/name")
names.each { |name| puts name.text }  # 输出:Alice, Bob

# 查询 id=1 的员工
employee = doc.xpath("//employee[@id='1']")
puts employee.first['id']  # 输出:1

# 查询年龄大于 25 的员工姓名
older_names = doc.xpath("//employee[age > 25]/name")
puts older_names.first.text  # 输出:Alice

常见 XPath 语法

  • //node:选择所有指定节点。
  • /node:选择直接子节点。
  • @attribute:选择属性。
  • [condition]:筛选条件(如 [age > 25])。
  • text():获取节点文本内容。

使用 CSS 选择器(替代 XPath)

Nokogiri 也支持 CSS 选择器,语法更简洁:

names = doc.css("employee name")
puts names.map(&:text)  # 输出:["Alice", "Bob"]

5. XSLT 转换

XSLT 用于将 XML 转换为其他格式(如 HTML)。Nokogiri 支持通过 xslt 方法应用 XSLT 样式表。

XSLT 示例

XML 文件employees.xml):

<?xml version="1.0" encoding="UTF-8"?>
<employees>
  <employee id="1">
    <name>Alice</name>
    <age>30</age>
  </employee>
  <employee id="2">
    <name>Bob</name>
    <age>25</age>
  </employee>
</employees>

XSLT 样式表style.xslt):

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <html>
      <body>
        <h1>Employee List</h1>
        <table border="1">
          <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Age</th>
          </tr>
          <xsl:for-each select="employees/employee">
            <tr>
              <td><xsl:value-of select="@id"/></td>
              <td><xsl:value-of select="name"/></td>
              <td><xsl:value-of select="age"/></td>
            </tr>
          </xsl:for-each>
        </table>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>

Ruby 代码

require 'nokogiri'

# 加载 XML 和 XSLT
xml = Nokogiri::XML(File.read('employees.xml'))
xslt = Nokogiri::XSLT(File.read('style.xslt'))

# 应用转换
result = xslt.transform(xml)
puts result.to_s

输出(HTML):

<html>
  <body>
    <h1>Employee List</h1>
    <table border="1">
      <tr>
        <th>ID</th>
        <th>Name</th>
        <th>Age</th>
      </tr>
      <tr>
        <td>1</td>
        <td>Alice</td>
        <td>30</td>
      </tr>
      <tr>
        <td>2</td>
        <td>Bob</td>
        <td>25</td>
      </tr>
    </table>
  </body>
</html>

说明

  • Nokogiri::XSLT:加载 XSLT 样式表。
  • transform:应用 XSLT 转换,返回结果文档。

6. 异常处理

处理 XML、XPath 或 XSLT 时可能遇到解析错误或文件缺失。

require 'nokogiri'

begin
  xml = Nokogiri::XML("<invalid>xml")  # 无效 XML
rescue Nokogiri::XML::SyntaxError => e
  puts "XML 解析错误: #{e.message}"
end

begin
  xslt = Nokogiri::XSLT(File.read('nonexistent.xslt'))
rescue Errno::ENOENT
  puts "XSLT 文件不存在"
end

常见异常

  • Nokogiri::XML::SyntaxError:XML 格式错误。
  • Errno::ENOENT:文件不存在。
  • Nokogiri::XSLT::ParseError:XSLT 样式表错误。

7. 注意事项

  • 性能
  • 大型 XML 文件使用流式解析(Nokogiri::XML::Reader):
    ruby Nokogiri::XML::Reader(File.open('large.xml')).each do |node| puts node.name if node.node_type == Nokogiri::XML::Reader::TYPE_ELEMENT end
  • 缓存 XSLT 样式表对象,避免重复解析。
  • 编码:确保 XML 和 XSLT 文件使用一致的编码(如 UTF-8)。
  • 安全性
  • 验证外部 XML 输入,防止 XML 注入(如实体扩展攻击)。
  • 使用 Nokogiri::XML(..., Nokogiri::XML::ParseOptions::NOENT) 禁用外部实体。
  • XPath vs CSS:CSS 选择器更直观,适合简单查询;XPath 更强大,适合复杂定位。
  • 调试:使用 to_xmlto_s 检查文档结构。
  • 依赖:确保 libxml2libxslt 正确安装,否则 Nokogiri 可能报错。

8. 综合示例

以下示例解析 XML,使用 XPath 提取数据,并通过 XSLT 转换为 HTML。

require 'nokogiri'

# 示例 XML
xml = <<~XML
  <employees>
    <employee id="1">
      <name>Alice</name>
      <age>30</age>
    </employee>
    <employee id="2">
      <name>Bob</name>
      <age>25</age>
    </employee>
  </employees>
XML

# 示例 XSLT
xslt = <<~XSLT
  <?xml version="1.0" encoding="UTF-8"?>
  <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
      <html>
        <body>
          <h1>Employees</h1>
          <ul>
            <xsl:for-each select="employees/employee">
              <li><xsl:value-of select="name"/> (Age: <xsl:value-of select="age"/>)</li>
            </xsl:for-each>
          </ul>
        </body>
      </html>
    </xsl:template>
  </xsl:stylesheet>
XSLT

begin
  # 解析 XML
  doc = Nokogiri::XML(xml)

  # XPath 查询
  names = doc.xpath("//employee[age > 25]/name").map(&:text)
  puts "年龄大于 25 的员工: #{names.join(', ')}"  # 输出:Alice

  # XSLT 转换
  xslt_doc = Nokogiri::XSLT(xslt)
  result = xslt_doc.transform(doc)
  puts result.to_s
rescue Nokogiri::XML::SyntaxError, Nokogiri::XSLT::ParseError => e
  puts "解析错误: #{e.message}"
end

输出

年龄大于 25 的员工: Alice
<html>
  <body>
    <h1>Employees</h1>
    <ul>
      <li>Alice (Age: 30)</li>
      <li>Bob (Age: 25)</li>
    </ul>
  </body>
</html>

9. 总结

Ruby 通过 Nokogiri 提供强大的 XML、XPath 和 XSLT 支持:

  • XML:使用 Nokogiri::XML 解析和修改,Nokogiri::XML::Builder 创建。
  • XPath:通过 xpath 方法查询节点,支持复杂条件。
  • XSLT:通过 Nokogiri::XSLT 转换 XML 为 HTML 或其他格式。
    注意编码一致性、性能优化(如流式解析)和安全性(如防止 XML 注入)。Nokogiri 是 Ruby 中处理 XML 的首选库,适合各种复杂场景。

如果你需要更复杂的示例(如大型 XML 处理、XSLT 参数传递)或有其他问题,请告诉我!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注