Modifying an HTML / XML Document¶
Changing text contents¶
Assuming we have the following HTML document:
@doc = Nokogiri::HTML::DocumentFragment.parse <<-EOHTML
<body>
<h1>Three's Company</h1>
<div>A love triangle.</div>
</body>
EOHTML
Let's change the header's text contents:
h1 = @doc.at_css "h1"
h1.content = "Snap, Crackle & Pop"
@doc.to_html
# => "<body>
# " +
# " <h1>Snap, Crackle & Pop</h1>
# " +
# " <div>A love triangle.</div>
# " +
# "
# " +
# "</body>"
You'll notice that, when you use #content=
, entities are properly
escaped. Pow!
Moving nodes¶
The simplest method of moving a node is assign its parent:
h1 = @doc.at_css "h1"
div = @doc.at_css "div"
h1.parent = div
@doc.to_html
# => "<body>
# " +
# "
# " +
# " <div>A love triangle.<h1>Three's Company</h1>
# " +
# "</div>
# " +
# "
# " +
# "</body>"
But you could also arrange it next to other nodes:
div.add_next_sibling(h1)
@doc.to_html
# => "<body>
# " +
# "
# " +
# " <div>A love triangle.</div>
# " +
# "<h1>Three's Company</h1>
# " +
# "
# " +
# "</body>"
Modifying Nodes and Attributes¶
h1.name = 'h2'
h1['class'] = 'show-title'
@doc.to_html
# => "<body>
# " +
# " <h2 class=\"show-title\">Three's Company</h2>
# " +
# " <div>A love triangle.</div>
# " +
# "
# " +
# "</body>"
Creating new nodes¶
Often the easiest thing to do is pass markup to one of the Node
methods to create siblings:
h1.add_next_sibling "<h3>1977 - 1984</h3>"
@doc.to_html
# => "<body>
# " +
# " <h1>Three's Company</h1>
# " +
# "<h3>1977 - 1984</h3>
# " +
# " <div>A love triangle.</div>
# " +
# "
# " +
# "</body>"
or you can manually create a node object, if you're a detail-oriented person:
h3 = Nokogiri::XML::Node.new "h3", @doc # !> Passing a Node as the second parameter to Node.new is deprecated. Please pass a Document instead, or prefer an alternative constructor like Node#add_child. This will become an error in Nokogiri v1.17.0.
h3.content = "1977 - 1984"
h1.add_next_sibling(h3)
@doc.to_html
# => "<body>
# " +
# " <h1>Three's Company</h1>
# " +
# "<h3>1977 - 1984</h3>
# " +
# " <div>A love triangle.</div>
# " +
# "
# " +
# "</body>"
Wrapping a NodeSet¶
If you wanted to wrap new HTML around each node in a Nodeset, here's an example of how to do it:
nodes = @doc.css "h1,div"
nodes.wrap("<div class='container'></div>")
@doc.to_html
# => "<body>
# " +
# " <div class=\"container\"><h1>Three's Company</h1></div>
# " +
# " <div class=\"container\"><div>A love triangle.</div></div>
# " +
# "
# " +
# "</body>"
Adding a Processing Instruction¶
(like <?xml-stylesheet?>)¶
If you want to add a processing instruction (a.k.a. "PI node"), like
an xml-stylesheet declaration, you should first create the node using
Nokogiri::XML::ProcessingInstruction.new
and then add it to the
document as a previous-sibling of the root node:
doc = Nokogiri::XML "<root>foo</root>"
doc.to_xml
# => "<?xml version=\"1.0\"?>
# " + "<root>foo</root>
# "
pi = Nokogiri::XML::ProcessingInstruction.new(doc, "xml-stylesheet",
'type="text/xsl" href="foo.xsl"')
doc.root.add_previous_sibling pi
doc.to_xml
# => "<?xml version=\"1.0\"?>
# " +
# "<?xml-stylesheet type=\"text/xsl\" href=\"foo.xsl\"?>
# " +
# "<root>foo</root>
# "