使用 Nokogiri 构建和解析 XML

2014/7/19 posted in  Ruby comments

构建 XML

  • 全新构建一个 XML

    builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
    xml.envelope {
    xml.header(:identifier => 'IDENTIFIER') {
    xml.type('TYPE')
    }
    xml.content
    }
    end
  • 在已有 XML 上追加子节点

    # 第一种方法
    content_element = builder.doc.at('content')
    content_element.inner_html = '<source>web</source>'
    # 第二种方法
    content_element.add_child('<result>SUCCESS</result>')
    # 此处调用的是 Nokogiri::XML::Element 的实例方法 <<
    content_element << '<reason>REASON</reason>'
    # 第三种方法
    Nokogiri::XML::Builder.with(builder.doc.root) do |xml|
    xml.footer('FOOTER')
    xml.destination {
    xml.ip('IP')
    # 此处调用的是 Nokogiri::XML::Builder 的实例方法 <<
    xml << '<port>80</port>'
    }
    end
  • 修改某个节点的内容

    reason_element = builder.doc.at('reason')
    reason_element.content = 'MODIFY REASON'
    
  • 替换某个节点

    reason_element.replace('<reason>REPLACE REASON</reason>')
    
  • 增加或修改某个节点的属性

    reason_element['type'] = 'warning'
    
  • 删除某个节点

    reason_element.unlink
    content_element.remove
    
  • 输出 XML

    builder.to_xml
    

解析 XML

假如我们有如下 XML

xml_string = '<?xml version="1.0" encoding="UTF-8"?>
<envelope>
  <header identifier="IDENTIFIER">
    <type>DOWNLOAD</type>
  </header>
  <content>
    <result>SUCCESS</result>
    <files>
      <file>a</file>
      <file>b</file>
      <file>c</file>
    </files>
  </content>
  <destination>
    <type>INNER NETWORK</type>
    <ip>IP</ip>
    <port>80</port>
  </destination>
</envelope>'

实例化 XML 对象

doc = Nokogiri::XML(xml_string) { |config|
  config.noblanks # 格式化 XML
}

根据 xpath 和 css 方式搜索整个XML节点,返回一个 Nokogiri::XML::NodeSet 对象

doc.xpath('//type')
doc.xpath('//header/type'

doc.css('type')
doc.css('header type')

doc.search('//type')
doc.search('type')

根据 xpath 和 css 方式返回最先找到的第一个 XML 节点,返回一个 Nokogiri::XML::Node 对象

doc.at_xpath('//type')
doc.at_css('type')
doc.at('//type')
doc.at('type')

获取某个节点的属性

header_element = doc.at('header')
header_element.attr('identifier') # 单个属性的值
header_element.attributes # 所有属性的 Hash
header_element.attribute_nodes # 所有属性的 Array

获取某个节点下的子节点

header_element.elements
header_element.element_children

获取某个节点的祖先节点

header_element.ancestors

获取某个节点下的第一个和最后一个子节点,没有则返回 nil

header_element.first_element_child
header_element.last_element_child

输出某个节点下 XML 字符串

header_element.canonicalize # 包含节点自身
header_element.inner_html # 仅输出子节点

Nokogiri 中 XML 节点对象的关系

  • Nokogiri::XML::NodeSet 包含多个 Nokogiri::XML::Node
  • 每个节点都是一个 Nokogiri::XML::Element 实例,继承自 Nokogiri::XML::Node
  • 节点间联系: ruby Nokogiri::XML::Element attributes={'name' => Nokogiri::XML::Attr} children=Nokogiri::XML::NodeSet