Class: Nokogiri::XML::Builder
Relationships & Source Files | |
Namespace Children | |
Classes:
| |
Extension / Inclusion / Inheritance Descendants | |
Subclasses:
|
|
Super Chains via Extension / Inclusion / Inheritance | |
Instance Chain:
|
|
Inherits: | Object |
Defined in: | lib/nokogiri/xml/builder.rb |
Overview
::Nokogiri
builder can be used for building ::Nokogiri::XML
and ::Nokogiri::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 ::Nokogiri::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. 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 ::Nokogiri::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 #[] 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 ::Nokogiri::XML
:
<?xml version="1.0"?>
<root xmlns:foo="bar">
<objects>
<foo:object class="classy" id="thing"/>
</objects>
</root>
Note the “foo:object” tag.
Namespace inheritance
In the Builder
context, children will inherit their parent’s namespace. This is the same behavior as if the underlying Document
set namespace_inheritance
to true
:
result = Nokogiri::XML::Builder.new do |xml|
xml["soapenv"].Envelope("xmlns:soapenv" => "http://schemas.xmlsoap.org/soap/envelope/") do
xml.Header
end
end
result.doc.to_xml
# => <?xml version="1.0" encoding="utf-8"?>
# <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
# <soapenv:Header/>
# </soapenv:Envelope>
Users may turn this behavior off by passing a keyword argument namespace_inheritance:false
to the initializer:
result = Nokogiri::XML::Builder.new(namespace_inheritance: false) do |xml|
xml["soapenv"].Envelope("xmlns:soapenv" => "http://schemas.xmlsoap.org/soap/envelope/") do
xml.Header
xml["soapenv"].Body # users may explicitly opt into the namespace
end
end
result.doc.to_xml
# => <?xml version="1.0" encoding="utf-8"?>
# <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
# <Header/>
# <soapenv:Body/>
# </soapenv:Envelope>
For more information on namespace inheritance, please see Document#namespace_inheritance
Document Types
To create a document type (DTD), use the #doc method to get the current context document. Then call Node#create_internal_subset to create the DTD
node.
For example, this Ruby:
builder = Nokogiri::XML::Builder.new do |xml|
xml.doc.create_internal_subset(
'html',
"-//W3C//DTD HTML 4.01 Transitional//EN",
"http://www.w3.org/TR/html4/loose.dtd"
)
xml.root do
xml.foo
end
end
puts builder.to_xml
Will output this xml:
<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<root>
<foo/>
</root>
Constant Summary
-
DEFAULT_DOCUMENT_OPTIONS =
# File 'lib/nokogiri/xml/builder.rb', line 267{ namespace_inheritance: true }
::Nokogiri::ClassResolver
- Included
Class Method Summary
-
.new(options = {}, root = nil, &block) ⇒ Builder
constructor
Create a new
Builder
object. -
.with(root, &block)
Create a builder with an existing root object.
Instance Attribute Summary
Instance Method Summary
-
#<<(string)
Append the given raw
::Nokogiri::XML
string
to the document. -
#[](ns)
Build a tag that is associated with namespace
ns
. -
#cdata(string)
Create a
CDATA
Node with content ofstring
-
#comment(string)
Create a
Comment
Node with content ofstring
-
#text(string)
Create a
Text
Node with content ofstring
-
#to_xml(*args)
Convert this
Builder
object to::Nokogiri::XML
. -
#insert(node, &block)
private
Insert
node
as a child of the currentNode
. - #method_missing(method, *args, &block) Internal use only
::Nokogiri::ClassResolver
- Included
#related_class | Find a class constant within the. |
Constructor Details
.new(options = {}, root = nil, &block) ⇒ Builder
# File 'lib/nokogiri/xml/builder.rb', line 307
def initialize( = {}, root = nil, &block) if root @doc = root.document @parent = root else @parent = @doc = ("Document").new end @context = nil @arity = nil @ns = nil = DEFAULT_DOCUMENT_OPTIONS.merge( ) .each do |k, v| @doc.send(:"#{k}=", v) end return unless block @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)
# File 'lib/nokogiri/xml/builder.rb', line 394
def method_missing(method, *args, &block) # :nodoc: if @context&.respond_to?(method) @context.send(method, *args, &block) else node = @doc.create_element(method.to_s.sub(/[_!]$/, ""), *args) do |n| # Set up the namespace if @ns.is_a?(Nokogiri::XML::Namespace) n.namespace = @ns @ns = nil end end if @ns.is_a?(Hash) node.namespace = node.namespace_definitions.find { |x| x.prefix == @ns[:pending] } if node.namespace.nil? raise ArgumentError, "Namespace #{@ns[:pending]} has not been defined" end @ns = nil end insert(node, &block) end end
Class Method Details
.with(root, &block)
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 ::
node.
For example:
doc = Nokogiri::XML(File.read('somedoc.xml'))
Nokogiri::XML::Builder.with(doc.at_css('some_tag')) do |xml|
# ... Use normal builder methods here ...
xml.awesome # add the "awesome" tag below "some_tag"
end
Instance Attribute Details
#arity (rw)
# File 'lib/nokogiri/xml/builder.rb', line 278
attr_accessor :arity # :nodoc:
#context (rw)
A context object for use when the block has no arguments
# File 'lib/nokogiri/xml/builder.rb', line 276
attr_accessor :context
#doc (rw)
The current Document
object being built
# File 'lib/nokogiri/xml/builder.rb', line 270
attr_accessor :doc
#parent (rw)
The parent of the current node being built
# File 'lib/nokogiri/xml/builder.rb', line 273
attr_accessor :parent
Instance Method Details
#<<(string)
Append the given raw ::Nokogiri::XML
string
to the document
#[](ns)
Build a tag that is associated with namespace ns
. Raises an ArgumentError if ns
has not been defined higher in the tree.
# File 'lib/nokogiri/xml/builder.rb', line 358
def [](ns) if @parent != @doc @ns = @parent.namespace_definitions.find { |x| x.prefix == ns.to_s } end 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 @ns = { pending: ns.to_s } self end
#cdata(string)
Create a CDATA
Node with content of string
#comment(string)
Create a Comment
Node with content of string
#insert(node, &block) (private)
Insert node
as a child of the current Node
# File 'lib/nokogiri/xml/builder.rb', line 423
def insert(node, &block) node = @parent.add_child(node) if block begin old_parent = @parent @parent = node @arity ||= block.arity if @arity <= 0 instance_eval(&block) else yield(self) end ensure @parent = old_parent end end NodeBuilder.new(node, self) end
#text(string)
Create a Text
Node with content of string
# File 'lib/nokogiri/xml/builder.rb', line 339
def text(string) insert(@doc.create_text_node(string)) end
#to_xml(*args)
Convert this Builder
object to ::Nokogiri::XML
# File 'lib/nokogiri/xml/builder.rb', line 377
def to_xml(*args) if Nokogiri.jruby? = args.first.is_a?(Hash) ? args.shift : {} unless [:save_with] [:save_with] = Node::SaveOptions::AS_BUILDER end args.insert(0, ) end @doc.to_xml(*args) end