如何向XML添加新节点

时间:2011-03-15 18:11:51

标签: ruby xml nokogiri

我有一个简单的XML文件items.xml:

 <?xml version="1.0" encoding="UTF-8" ?>

<items>
  <item>
    <name>mouse</name>
    <manufacturer>Logicteh</manufacturer>
  </item>
  <item>
    <name>keyboard</name>
    <manufacturer>Logitech - Inc.</manufacturer>
  </item>
  <item>
    <name>webcam</name>
    <manufacturer>Logistech</manufacturer>
  </item>
</items>

我正在尝试使用以下代码插入新节点:

require 'rubygems'
require 'nokogiri'

f = File.open('items.xml')
@items = Nokogiri::XML(f)
f.close

price = Nokogiri::XML::Node.new "price", @items
price.content = "10"

@items.xpath('//items/item/manufacturer').each do |node|
  node.add_next_sibling(price)
end

file = File.open("items_fixed.xml",'w')
file.puts @items.to_xml
file.close

但是,此代码仅在最后一个<manufacturer>节点之后添加一个新节点,items_fixed.xml:

<?xml version="1.0" encoding="UTF-8"?>
<items>
  <item>
    <name>mouse</name>
    <manufacturer>Logitech</manufacturer>
  </item>
  <item>
    <name>keyboard</name>
    <manufacturer>Logitech</manufacturer>
  </item>
  <item>
    <name>webcam</name>
    <manufacturer>Logitech</manufacturer><price>10</price>
  </item>
</items>

为什么?

2 个答案:

答案 0 :(得分:13)

区分Node(树中特定位置的特定结构化XML数据)和“节点模板”(数据结构)将会很有帮助。

Nokogiri(以及大多数其他XML库)只允许您指定Node,而不是节点模板。因此,当您创建price = Nokogiri::XML::Node.new "price", @items时,您拥有属于特定位置的特定数据,但尚未定义该位置。

当您将其添加到第一个<item>时,您定义了它的位置。当您将其添加到第二个<item>时,您将其从其位置连根拔起并将其放在新位置。此时此Node仅出现在第二个<item>中。当您向每个项目添加相同的Node时,此操作会继续,直到您到达节点所在的最后<item>

Nokogiri没有任何方法来指定节点模板。你需要做的是:

@items.xpath('//items/item/manufacturer').each do |node|
  price = Nokogiri::XML::Node.new "price", @items
  price.content = "10"
  node.add_next_sibling(price)
end

答案 1 :(得分:2)

我从这开始:

require 'nokogiri'

doc = Nokogiri::XML(<<EOT)
<?xml version="1.0" encoding="UTF-8"?>
<items>
  <item>
    <name>mouse</name>
    <manufacturer>Logitech</manufacturer>
  </item>
  <item>
    <name>keyboard</name>
    <manufacturer>Logitech - Inc.</manufacturer>
  </item>
</items>
EOT

doc.search('manufacturer').each { |n| n.after('<price>10</price>') }

结果是:

puts doc.to_xml
# >> <?xml version="1.0" encoding="UTF-8"?>
# >> <items>
# >>   <item>
# >>     <name>mouse</name>
# >>     <manufacturer>Logitech</manufacturer><price>10</price>
# >>   </item>
# >>   <item>
# >>     <name>keyboard</name>
# >>     <manufacturer>Logitech - Inc.</manufacturer><price>10</price>
# >>   </item>
# >> </items>

很容易在此基础上插入不同的价格值。

相关问题