Arnold Roa
Arnold Roa

Reputation: 7718

How I can add an element?

I'm doing this:

targets = @xml.xpath("./target")
if targets.empty?
  targets << Nokogiri::XML::Node.new('target', @xml)
end

However the @xml is still without my target. What can I do in order to update the original @xml?

Upvotes: 0

Views: 245

Answers (2)

Arnold Roa
Arnold Roa

Reputation: 7718

I end doing this, works fine.

targets = @xml.xpath("./target")
if targets.empty?
  targets << Nokogiri::XML::Node.new('target', @xml)
  @xml.add_child(targets.first)
end

Upvotes: 0

the Tin Man
the Tin Man

Reputation: 160551

It's a lot easier than that:

require 'nokogiri'

doc = Nokogiri::XML(<<EOT)
<root>
  <node>
  </node>
</root>
EOT

doc.at('node').children = '<child>foo</child>'
doc.to_xml
# => "<?xml version=\"1.0\"?>\n<root>\n  <node><child>foo</child></node>\n</root>\n"

children= is smart enough to see what you're passing in and will do the dirty work for you. So just use a string to define the new node(s) and tell Nokogiri where to insert it.


doc.at('node').class   # => Nokogiri::XML::Element
doc.at('//node').class # => Nokogiri::XML::Element

doc.search('node').first   # => #<Nokogiri::XML::Element:0x3fd1a88c5c08 name="node" children=[#<Nokogiri::XML::Text:0x3fd1a88eda3c "\n  ">]>
doc.search('//node').first # => #<Nokogiri::XML::Element:0x3fd1a88c5c08 name="node" children=[#<Nokogiri::XML::Text:0x3fd1a88eda3c "\n  ">]>

search is the generic "find a node" method that will take either CSS or XPath selectors. at is equivalent to search('some selector').first. at_css and at_xpath are the specific equivalents of at, just as css and xpath are to search. Use the specific versions if you want, but in general I use the generic versions.


You can't use:

targets = @xml.xpath("./target")
if targets.empty?
  targets << Nokogiri::XML::Node.new('target', @xml)
end

targets would be [] (actually an empty NodeSet) if ./target doesn't exist in the DOM. You can't append a node to [], because NodeSet doesn't have an idea of what you're talking about, resulting in a undefined method 'children=' for nil:NilClass (NoMethodError) exception.

Instead you MUST find the specific location where you want to insert the node. at is good for that since it finds just the first location. Of course, if you want to look for multiple places to modify something use search then iterate over the returned NodeSet and modify based on the individual nodes returned.

Upvotes: 1

Related Questions