Class: Nokogiri::XML::Builder
- Inherits:
-
Object
- Object
- Nokogiri::XML::Builder
- Defined in:
- lib/nokogiri/xml/builder.rb
Overview
Nokogiri builder can be used for building XML and HTML documents.
Synopsis:
builder = Nokogiri::XML::Builder.new do |xml|
xml.root {
xml.products {
xml. {
xml.id_ "10"
xml.name "Awesome widget"
}
}
}
end
puts builder.to_xml
Will output:
<?xml version="1.0"?>
<root>
<products>
<widget>
<id>10</id>
<name>Awesome widget</name>
</widget>
</products>
</root>
Builder scope
The builder allows two forms. When the builder is supplied with a block that has a parameter, the outside scope is maintained. This means you can access variables that are outside your builder. If you don’t need outside scope, you can use the builder without the “xml” prefix like this:
builder = Nokogiri::XML::Builder.new do
root {
products {
{
id_ "10"
name "Awesome widget"
}
}
}
end
Special Tags
The builder works by taking advantage of method_missing. Unfortunately some methods are defined in ruby that are difficult or dangerous to remove. You may want to create tags with the name “type”, “class”, and “id” for example. In that case, you can use an underscore to disambiguate your tag name from the method call.
Here is an example of using the underscore to disambiguate tag names from ruby methods:
@objects = [Object.new, Object.new, Object.new]
builder = Nokogiri::XML::Builder.new do |xml|
xml.root {
xml.objects {
@objects.each do |o|
xml.object {
xml.type_ o.type
xml.class_ o.class.name
xml.id_ o.id
}
end
}
}
end
puts builder.to_xml
The underscore may be used with any tag name, and the last underscore will just be removed. This code will output the following XML:
<?xml version="1.0"?>
<root>
<objects>
<object>
<type>Object</type>
<class>Object</class>
<id>48390</id>
</object>
<object>
<type>Object</type>
<class>Object</class>
<id>48380</id>
</object>
<object>
<type>Object</type>
<class>Object</class>
<id>48370</id>
</object>
</objects>
</root>
Tag Attributes
Tag attributes may be supplied as method arguments. Here is our previous example, but using attributes rather than tags:
@objects = [Object.new, Object.new, Object.new]
builder = Nokogiri::XML::Builder.new do |xml|
xml.root {
xml.objects {
@objects.each do |o|
xml.object(:type => o.type, :class => o.class, :id => o.id)
end
}
}
end
puts builder.to_xml
Tag Attribute Short Cuts
A couple attribute short cuts are available when building tags. The short cuts are available by special method calls when building a tag.
This example builds an “object” tag with the class attribute “classy” and the id of “thing”:
builder = Nokogiri::XML::Builder.new do |xml|
xml.root {
xml.objects {
xml.object.classy.thing!
}
}
end
puts builder.to_xml
Which will output:
<?xml version="1.0"?>
<root>
<objects>
<object class="classy" id="thing"/>
</objects>
</root>
All other options are still supported with this syntax, including blocks and extra tag attributes.
Namespaces
Namespaces are added similarly to attributes. Nokogiri::XML::Builder assumes that when an attribute starts with “xmlns”, it is meant to be a namespace:
builder = Nokogiri::XML::Builder.new { |xml|
xml.root('xmlns' => 'default', 'xmlns:foo' => 'bar') do
xml.tenderlove
end
}
puts builder.to_xml
Will output XML like this:
<?xml version="1.0"?>
<root xmlns:foo="bar" xmlns="default">
<tenderlove/>
</root>
Referencing declared namespaces
Tags that reference non-default namespaces (i.e. a tag “foo:bar”) can be built by using the Nokogiri::XML::Builder#[] method.
For example:
builder = Nokogiri::XML::Builder.new do |xml|
xml.root('xmlns:foo' => 'bar') {
xml.objects {
xml['foo'].object.classy.thing!
}
}
end
puts builder.to_xml
Will output this XML:
<?xml version="1.0"?>
<root xmlns:foo="bar">
<objects>
<foo:object class="classy" id="thing"/>
</objects>
</root>
Note the “foo:object” tag.
Direct Known Subclasses
Defined Under Namespace
Classes: NodeBuilder
Instance Attribute Summary collapse
-
#arity ⇒ Object
:nodoc:.
-
#context ⇒ Object
A context object for use when the block has no arguments.
-
#doc ⇒ Object
The current Document object being built.
-
#parent ⇒ Object
The parent of the current node being built.
Class Method Summary collapse
-
.with(root, &block) ⇒ Object
Create a builder with an existing root object.
Instance Method Summary collapse
-
#<<(string) ⇒ Object
Append the given raw XML
string
to the document. -
#[](ns) ⇒ Object
Build a tag that is associated with namespace
ns
. -
#cdata(string) ⇒ Object
Create a CDATA Node with content of
string
. -
#initialize(options = {}, root = nil, &block) ⇒ Builder
constructor
Create a new Builder object.
-
#method_missing(method, *args, &block) ⇒ Object
:nodoc:.
-
#text(string) ⇒ Object
Create a Text Node with content of
string
. -
#to_xml(*args) ⇒ Object
Convert this Builder object to XML.
Constructor Details
#initialize(options = {}, root = nil, &block) ⇒ Builder
Create a new Builder object. options
are sent to the top level Document that is being built.
Building a document with a particular encoding for example:
Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
...
end
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
# File 'lib/nokogiri/xml/builder.rb', line 236 def initialize = {}, root = nil, &block if root @doc = root.document @parent = root else namespace = self.class.name.split('::') namespace[-1] = 'Document' @doc = eval(namespace.join('::')).new @parent = @doc end @context = nil @arity = nil @ns = nil .each do |k,v| @doc.send(:"#{k}=", v) end return unless block_given? @arity = block.arity if @arity <= 0 @context = eval('self', block.binding) instance_eval(&block) else yield self end @parent = @doc end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method, *args, &block) ⇒ Object
:nodoc:
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 |
# File 'lib/nokogiri/xml/builder.rb', line 310 def method_missing method, *args, &block # :nodoc: if @context && @context.respond_to?(method) @context.send(method, *args, &block) else node = @doc.create_element(method.to_s.sub(/[_!]$/, '')) { |n| # Set up the namespace if @ns n.namespace = @ns @ns = nil end args.each do |arg| case arg when Hash arg.each { |k,v| key = k.to_s if key =~ /^xmlns(:\w+)?$/ ns_name = key.split(":", 2)[1] n.add_namespace_definition ns_name, v next end n[k.to_s] = v.to_s } else n.content = arg end end } insert(node, &block) end end |
Instance Attribute Details
#arity ⇒ Object
:nodoc:
207 208 209 |
# File 'lib/nokogiri/xml/builder.rb', line 207 def arity @arity end |
#context ⇒ Object
A context object for use when the block has no arguments
205 206 207 |
# File 'lib/nokogiri/xml/builder.rb', line 205 def context @context end |
#doc ⇒ Object
The current Document object being built
199 200 201 |
# File 'lib/nokogiri/xml/builder.rb', line 199 def doc @doc end |
#parent ⇒ Object
The parent of the current node being built
202 203 204 |
# File 'lib/nokogiri/xml/builder.rb', line 202 def parent @parent end |
Class Method Details
.with(root, &block) ⇒ Object
Create a builder with an existing root object. This is for use when you have an existing document that you would like to augment with builder methods. The builder context created will start with the given root
node.
For example:
doc = Nokogiri::XML(open('somedoc.xml'))
Nokogiri::XML::Builder.with(doc.at('some_tag')) do |xml|
# ... Use normal builder methods here ...
xml.awesome # add the "awesome" tag below "some_tag"
end
223 224 225 |
# File 'lib/nokogiri/xml/builder.rb', line 223 def self.with root, &block builder = self.new({}, root, &block) end |
Instance Method Details
#<<(string) ⇒ Object
Append the given raw XML string
to the document
306 307 308 |
# File 'lib/nokogiri/xml/builder.rb', line 306 def << string @doc.fragment(string).children.each { |x| insert(x) } end |
#[](ns) ⇒ Object
Build a tag that is associated with namespace ns
. Raises an ArgumentError if ns
has not been defined higher in the tree.
285 286 287 288 289 290 291 292 293 294 295 296 |
# File 'lib/nokogiri/xml/builder.rb', line 285 def [] ns @ns = @parent.namespace_definitions.find { |x| x.prefix == ns.to_s } return self if @ns @parent.ancestors.each do |a| next if a == doc @ns = a.namespace_definitions.find { |x| x.prefix == ns.to_s } return self if @ns end raise ArgumentError, "Namespace #{ns} has not been defined" end |
#cdata(string) ⇒ Object
Create a CDATA Node with content of string
277 278 279 280 |
# File 'lib/nokogiri/xml/builder.rb', line 277 def cdata string node = Nokogiri::XML::CDATA.new(@doc, string.to_s) insert(node) end |
#text(string) ⇒ Object
Create a Text Node with content of string
271 272 273 |
# File 'lib/nokogiri/xml/builder.rb', line 271 def text string insert @doc.create_text_node string end |
#to_xml(*args) ⇒ Object
Convert this Builder object to XML
300 301 302 |
# File 'lib/nokogiri/xml/builder.rb', line 300 def to_xml(*args) @doc.to_xml(*args) end |