I'm using Ruby to inject new elements around selected XML nodes. Like this:
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 )
This is the structure that I want:
<fmxmlsnippet type='FMObjectList'>
<node/>
<Step name='Variable'/>
<node/>
<Step name='Comment'/>
<node/>
<Step name='Variable'/>
<node/>
</fmxmlsnippet>'
But this is what I'm getting with the code above:
<fmxmlsnippet type='FMObjectList'>
<Step name='Variable'/>
<Step name='Comment'/>
开发者_StackOverflow中文版<Step name='Variable'/>
<node/>
</fmxmlsnippet>'
What am I doing wrong?
I'm guessing it has to do with my lack of understanding of how the block is getting executed. The path seems to work because it can print the desired elements' attributes just fine.
I'd like to stay with REXML because it's part of the Ruby distribution, but I'd consider Nokogiri if I can get it working that way.
This is using Nokogiri. I prefer and recommend it because it's very flexible and the defacto standard for Ruby these days.
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.
精彩评论