2011-03-15 108 views
6

我有一个简单的XML文件,items.xml:如何将新节点添加到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> 

为什么?

+0

你让它太难了。 Nokogiri可以轻松地使用字符串添加节点,然后将其解析为新节点。请参阅下面的答案。 – 2016-08-19 21:19:15

回答

12

区分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 
+0

我看到您在调试器中解释的确切行为,但无法理解它。谢谢你的解释和你的回答! – 2011-03-15 18:26:07

+2

或者,您可能只需使用['Node#dup'](http://nokogiri.rubyforge.org/nokogiri/Nokogiri/XML/Node.html#M000469)在将节点插入新位置之前克隆节点。 – Phrogz 2011-03-21 19:40:57

+0

很好的解释..自从去年3-4天以来,我遇到了同样的问题。现在我发现它为什么会发生。感谢OP和你。 – 2015-02-03 08:48:25

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> 

可以很容易地建立在此插入不同的值价格。