0

我正在使用 Ruby 在选定的 XML 节点周围注入新元素。像这样:

require 'rexml/document'
include REXML

xml = <<EOF
<fmxmlsnippet type="FMObjectList">
    <Step name="Variable"/>
    <Step name="Comment"/>
    <Step name="Variable"/>
</fmxmlsnippet>
EOF

doc = Document.new xml
el = Element.new 'node'
doc.elements.each( "//Step[@name=\"Variable\"]"){ |e|
  e.previous_sibling = el
  e.next_sibling = el
}
doc.write( $stdout, 2 )

这是我想要的结构:

<fmxmlsnippet type='FMObjectList'>
    <node/>
    <Step name='Variable'/>
    <node/>
    <Step name='Comment'/>
    <node/>
    <Step name='Variable'/>
    <node/>
</fmxmlsnippet>' 

但这就是我用上面的代码得到的:

<fmxmlsnippet type='FMObjectList'>
    <Step name='Variable'/>
    <Step name='Comment'/>
    <Step name='Variable'/>
    <node/>
</fmxmlsnippet>' 

我究竟做错了什么?

我猜这与我对块的执行方式缺乏了解有关。该路径似乎有效,因为它可以很好地打印所需元素的属性。

我想继续使用 REXML,因为它是 Ruby 发行版的一部分,但如果我能让它以这种方式工作,我会考虑 Nokogiri。

4

1 回答 1

2

这是使用Nokogiri。我更喜欢并推荐它,因为它非常灵活并且是当今 Ruby 的事实标准。

xml = <<EOT
<fmxmlsnippet type="FMObjectList">
    <Step name="Variable"/>
    <Step name="Comment"/>
    <Step name="Variable"/>
</fmxmlsnippet>
EOT

require 'nokogiri'

doc = Nokogiri::XML(xml)

doc.search('Step[name="Variable"]').each do |s|
  s.add_previous_sibling('<node/>')
  s.add_next_sibling('<node/>')
end

puts doc.to_xml

# >> <?xml version="1.0"?>
# >> <fmxmlsnippet type="FMObjectList">
# >>     <node/><Step name="Variable"/><node/>
# >>     <Step name="Comment"/>
# >>     <node/><Step name="Variable"/><node/>
# >> </fmxmlsnippet>

It's using CSS accessors to find the Step nodes with name="Variable". For each one encountered it adds a previous and next sibling <node>. Nokogiri supports XPath also so '//Step[@name="Variable"]' would work just as well.

于 2011-06-21T05:27:15.333 回答