【问题标题】:How to add a new node to XML如何向 XML 添加新节点
【发布时间】:2011-03-15 18:11:51
【问题描述】:

我有一个简单的 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

但是,此代码仅在最后一个 &lt;manufacturer&gt; 节点 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>

为什么?

【问题讨论】:

  • 你太难了。 Nokogiri 可以轻松地使用字符串添加节点,然后将其解析为新节点。请参阅下面的答案。

标签: ruby xml nokogiri


【解决方案1】:

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

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

当您将它添加到第一个 &lt;item&gt; 时,您定义了它的位置。当您将它添加到第二个&lt;item&gt; 时,您将它从原来的位置连根拔起并放在一个新的位置。那时这个Node 只出现在第二个&lt;item&gt; 中。当您将相同的Node 添加到每个项目时,此过程将继续,直到您到达最后一个&lt;item&gt;,即节点所在的位置。

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

【讨论】:

  • 我看到了您在调试器中解释的确切行为,但无法理解。感谢您的解释和回答!
  • 或者,您可能只想使用Node#dup 克隆节点,然后再将其插入新位置。
  • 很好的解释.. 自上次 3-4 天以来我遇到了同样的问题。现在我知道为什么会这样了。感谢 OP 和你。
  • 比这更容易。看我的例子。
【解决方案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>

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多