How to add attribute to Nokogiri node?
I believe you should just need to use the []= method, i.e.
node['foo'] = 'bar'
You could also use node.set_attribute('foo', 'bar')
.
How to add an attribute to Nokogiri XML builder?
Add the attributes to the node like this
xml = Nokogiri::XML::Builder.new do |x|
x.root do
x.book(isbn: 1235) do
x.text('Don Quixot')
end
end
end.doc
Or, after re-rereading your question perhaps you wanted to add it to the parent further in the do block. In that case, this works:
xml = Nokogiri::XML::Builder.new do |x|
x.root do
x.book do
x.parent.set_attribute('isbn', 12345)
x.text('Don Quixot')
end
end
end.doc
Generates:
<?xml version="1.0"?>
<root>
<book isbn="1235">Don Quixot</book>
</root>
Setting an attribute in a Nokogiri::XML::NodeSet with css
The problem has little to do with CSS, since Nokogiri uses CSS selectors as an alternative to using XPath selectors, and both are only used to provide a path to a node, or nodes.
It looks like you're overthinking this, and making it harder than it needs to be. Here's what I'd do:
require 'nokogiri'
doc = Nokogiri::XML(<<EOT)
<xml>
<foo>
<Object>bar</Object>
</foo>
</xml>
EOT
doc.at('Object')["Id"] = Time.now.to_s
Looking at doc
at this point shows:
puts doc.to_xml
# >> <?xml version="1.0"?>
# >> <xml>
# >> <foo>
# >> <Object Id="2014-01-28 19:13:32 -0700">bar</Object>
# >> </foo>
# >> </xml>
It's really important to understand the difference between at
, at_css
and at_xpath
, which return the first matching Node, and search
, css
and xpath
, which return NodeSets. A NodeSet is akin to an array containing Nodes. When you know that, your statement:
doc.css('Object').attr("Id").value = timestamp
won't make much sense, especially since that's not how the attr
method is defined:
attr(key, value = nil, &blk)
You'd need to use:
doc.css('Object').attr("Id", value)
which would assign value
to all Id
attributes for every <Object>
node in the document.
But, again, that's not the right choice, instead you should use at
or at_css
to return the single node.
This was fine until the situation where 'Object' doesn't exist
If no <Object>
node exists, then it gets more interesting, and you have to determine what to do. You can insert it, or, you can simply move along and do nothing.
To see if a node exists is simple:
object_node = doc.at('Object')
if object_node
object_node['Id'] = Time.now.to_s
else
# ... insert it
end
To insert a node involves locating the place you want to insert it, then add it:
doc.at('foo').add_child("<Object Id='#{ Time.now }'>baz</Object>")
puts doc.to_xml
# >> <?xml version="1.0"?>
# >> <xml>
# >> <foo>
# >> <Object>bar</Object>
# >> <Object Id="2014-01-28 19:39:38 -0700">baz</Object></foo>
# >> </xml>
I didn't try to make the XML output pretty, which isn't important in XML, it merely needs to be syntactically correct.
Also note that it's possible to insert a node, or nodes, by defining them as a string of XML. Nokogiri will parse it into the appropriate XML and graft it in where you said. You could also go the long route by define a NodeSet or Node, then inserting it, but, in general, that makes uglier code and causes you to do a lot more work, which results in less readable code for those who follow in your footsteps maintaining the source.
How to get the value of an attribute using Nokogiri
It's idiomatic to access parameter values by treating the node as a hash:
require 'nokogiri'
doc = Nokogiri::HTML('<div class="foo"></div>')
doc.at('div')['class'] # => "foo"
And, just like a hash, you can assign to it too:
doc.at('div')['class'] = 'bar'
puts doc.to_html
# >> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
# >> <html><body><div class="bar"></div></body></html>
See []
and []=
"Modifying Nodes and Attributes" in the documentation.
Ruby + Nokogiri: How to create XML node with attribute=value?
I would do as below :
require 'nokogiri'
builder = Nokogiri::XML::Builder.new do |xml|
xml.CityStateLookupRequest('userid' => 'xxxxxx' ) {
xml.zip("id" => '10'){
xml.Zip5 '90210'
}
}
end
puts builder.to_xml
# >> <?xml version="1.0"?>
# >> <CityStateLookupRequest userid="xxxxxx">
# >> <zip id="10">
# >> <Zip5>90210</Zip5>
# >> </zip>
# >> </CityStateLookupRequest>
How can I get nokogiri to select node attributes and add them to other nodes?
next_sibling
should do the job
require 'rubygems'
require 'nokogiri'
frag = Nokogiri::XML(DATA)
frag.css('title').each { |t| t['id'] = "ID#{t.next_sibling.next_sibling['number']}" }
puts frag.to_xml
__END__
<root>
<title>Section X</title>
<paragraph number="1">Stuff</paragraph>
<title>Section Y</title>
<paragraph number="2">Stuff</paragraph>
</root>
Because whitespace is also a node, you have to call next_sibling
twice. Maybe there is a way to avoid this.
Alternatively you can use an xpath expression to select the number attribute of the next paragraph
t['id'] = "ID#{t.xpath('following-sibling::paragraph/@number').first}"
Related Topics
How to Remotely Inspect the Data in My Rediscloud Dbs
Lion: Problem with Rvm Installing Rubies - Problem Related to Openssl
Does Anyone Know How to Appropriately Deal with User Timezones in Rails 2.3
Heroku: Pg::Connectionbad: Could Not Connect to Server: Connection Refused
Ruby 'split': Invalid Byte Sequence in Utf-8 (Argumenterror)
How to Make a Custom Environment in Rails a Default Environment
Ruby String#Scan Equivalent to Return Matchdata
How to Access a Variable Within a Heredoc in Ruby
Detecting Linux Distribution/Platform in Ruby
Rails Routing: Giving Default Values for Path Helpers
Package Configuration for Libffi Is Not Found in MACos While Installing Travis-Cli
Rails 3/ Git/ Bundler Fatal Could Not Parse Object