CINXE.COM
Mojo::DOM - Minimalistic HTML/XML DOM parser with CSS selectors
<!doctype html><html> <head> <link rel="apple-touch-icon" href="/mojolicious/touch-icon.png"> <link rel="apple-touch-icon" sizes="152x152" href="/mojolicious/touch-icon-152x152.png"> <link rel="apple-touch-icon" sizes="167x167" href="/mojolicious/touch-icon-167x167.png"> <link rel="apple-touch-icon" sizes="180x180" href="/mojolicious/touch-icon-180x180.png"> <link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="Mojolicious" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>Mojo::DOM - Minimalistic HTML/XML DOM parser with CSS selectors</title> <script src="/mojolicious/jquery/jquery.js"></script> <script src="/mojolicious/highlight.js/highlight.min.js"></script> <link href="/mojolicious/highlight.js/highlight-mojo-light.css" rel="stylesheet"> <script>hljs.initHighlightingOnLoad();</script> <script src="/mojolicious/bootstrap/bootstrap.js"></script> <link href="/mojolicious/bootstrap/bootstrap.css" rel="stylesheet"> <link href="/mojolicious/fontawesome/fontawesome.css" rel="stylesheet"> <link href="/app.css?v=3" rel="stylesheet"> <link href="/mojodocs.css" rel="stylesheet"> </head> <body><a id="toc"></a> <header> <nav class="navbar navbar-expand-lg navbar-dark mojobar"> <a href="https://mojolicious.org" id="mojobar-brand" class="navbar-brand"> <picture> <img src="/mojo/logo-white.png" srcset="/mojo/logo-white-2x.png 2x"> </picture> </a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div id="navbarNav" class="collapse navbar-collapse"> <ul class="navbar-nav mr-auto"> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> Documentation </a> <div class="dropdown-menu" aria-labelledby="navbarDropdown"> <a class="dropdown-item" href="https://docs.mojolicious.org">Overview</a> <div class="dropdown-divider"></div> <a class="dropdown-item" href="https://docs.mojolicious.org/Mojolicious/Guides/Tutorial">Tutorial</a> <a class="dropdown-item" href="https://docs.mojolicious.org/Mojolicious/Guides/Growing">Growing</a> <a class="dropdown-item" href="https://docs.mojolicious.org/Mojolicious/Guides/Routing">Routing</a> <a class="dropdown-item" href="https://docs.mojolicious.org/Mojolicious/Guides/Rendering">Rendering</a> <a class="dropdown-item" href="https://docs.mojolicious.org/Mojolicious/Guides/Testing">Testing</a> <a class="dropdown-item" href="https://docs.mojolicious.org/Mojolicious/Guides/Cookbook">Cookbook</a> <a class="dropdown-item" href="https://docs.mojolicious.org/Mojolicious/Guides/Contributing">Contributing</a> <a class="dropdown-item" href="https://docs.mojolicious.org/Mojolicious/Guides/FAQ">FAQ</a> <div class="dropdown-divider"></div> <a class="dropdown-item" href="https://docs.mojolicious.org#API">API</a> </div> </li> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" href="#" id="communityDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> Community </a> <div class="dropdown-menu" aria-labelledby="communityDropdown"> <a class="dropdown-item" href="https://web.libera.chat/#mojo">IRC</a> <a class="dropdown-item" href="https://forum.mojolicious.org">Forum</a> <a class="dropdown-item" href="https://fosstodon.org/@mojolicious">Mastodon</a> <a class="dropdown-item" href="https://www.linkedin.com/groups/8963713/">LinkedIn</a> <a class="dropdown-item" href="https://github.com/mojolicious/mojo/wiki">Wiki</a> <a class="dropdown-item" href="https://metacpan.org/release/Mojolicious/">CPAN</a> </div> </li> <li class="nav-item"> <a class="nav-link" href="https://github.com/mojolicious/mojo/">Contribute on GitHub</a> </li> </ul> <a class="navbar-brand" href="https://mojojs.org"> <picture> <img src="/mojolicious/mojojs-white.png" srcset="/mojolicious/mojojs-white-2x.png 2x"> </picture> </a> <form action="https://www.google.com/cse" target="_blank" class="form-inline my-2 my-lg-0"> <input name="cx" type="hidden" value="014527573091551588235:pwfplkjpgbi"> <input name="ie" type="hidden" value="UTF-8"> <input name="q" placeholder="Search..." type="search"> </form> </div> </nav> </header> <div class="container-fluid"> <div class="row flex-wrap"> <aside class="col-sm-12 col-md-4 col-lg-2 mojo-sidebar"> <form class="mojo-version d-flex align-items-center"> <fieldset disabled> <input type="text" id="disabledTextInput" class="form-control" placeholder="v9.40"> </fieldset> </form> <ul> <li> <a href="#NAME"><b>NAME</b></a> </li> <li> <a href="#SYNOPSIS"><b>SYNOPSIS</b></a> </li> <li> <a href="#DESCRIPTION"><b>DESCRIPTION</b></a> </li> <li> <a href="#NODES-AND-ELEMENTS"><b>NODES AND ELEMENTS</b></a> </li> <li> <a href="#HTML-AND-XML"><b>HTML AND XML</b></a> </li> <li> <a href="#METHODS"><b>METHODS</b></a> <ul> <li><a href="#all_text">all_text</a></li> <li><a href="#ancestors">ancestors</a></li> <li><a href="#append">append</a></li> <li><a href="#append_content">append_content</a></li> <li><a href="#at">at</a></li> <li><a href="#attr">attr</a></li> <li><a href="#child_nodes">child_nodes</a></li> <li><a href="#children">children</a></li> <li><a href="#content">content</a></li> <li><a href="#descendant_nodes">descendant_nodes</a></li> <li><a href="#find">find</a></li> <li><a href="#following">following</a></li> <li><a href="#following_nodes">following_nodes</a></li> <li><a href="#matches">matches</a></li> <li><a href="#namespace">namespace</a></li> <li><a href="#new">new</a></li> <li><a href="#new_tag">new_tag</a></li> <li><a href="#next">next</a></li> <li><a href="#next_node">next_node</a></li> <li><a href="#parent">parent</a></li> <li><a href="#parse">parse</a></li> <li><a href="#preceding">preceding</a></li> <li><a href="#preceding_nodes">preceding_nodes</a></li> <li><a href="#prepend">prepend</a></li> <li><a href="#prepend_content">prepend_content</a></li> <li><a href="#previous">previous</a></li> <li><a href="#previous_node">previous_node</a></li> <li><a href="#remove">remove</a></li> <li><a href="#replace">replace</a></li> <li><a href="#root">root</a></li> <li><a href="#selector">selector</a></li> <li><a href="#strip">strip</a></li> <li><a href="#tag">tag</a></li> <li><a href="#tap">tap</a></li> <li><a href="#text">text</a></li> <li><a href="#to_string">to_string</a></li> <li><a href="#tree">tree</a></li> <li><a href="#type">type</a></li> <li><a href="#val">val</a></li> <li><a href="#with_roles">with_roles</a></li> <li><a href="#wrap">wrap</a></li> <li><a href="#wrap_content">wrap_content</a></li> <li><a href="#xml">xml</a></li> </ul> </li> <li> <a href="#OPERATORS"><b>OPERATORS</b></a> <ul> <li><a href="#array">array</a></li> <li><a href="#bool">bool</a></li> <li><a href="#hash">hash</a></li> <li><a href="#stringify">stringify</a></li> </ul> </li> <li> <a href="#SEE-ALSO"><b>SEE ALSO</b></a> </li> </ul> </aside> <main class="col-sm-12 col-md-8 col-lg-10 py-md-3 pl-md-5 mojo-main"> <div class="mojo-docinfo"> <div> <div class="mojo-docnav"> <a class="nav-link" alt="API" href="https://docs.mojolicious.org#API"><i class="fas fa-book"></i></a> </div> Module: <a href="http://docs.mojolicious.org/Mojo">Mojo</a>::<a href="http://docs.mojolicious.org/Mojo/DOM">DOM</a> </div> </div> <div class="mojo-external"> <a class="btn btn-outline-secondary btn-sm" href="http://docs.mojolicious.org/Mojo/DOM.txt" role="button"> Source </a> <a class="btn btn-outline-secondary btn-sm" href="https://metacpan.org/pod/Mojo::DOM" role="button">CPAN</a> </div> <div class="mojo-perldoc"> <h1 id="NAME"><a class="permalink" href="#NAME">#</a><a href="#toc">NAME</a></h1> <p>Mojo::DOM - Minimalistic HTML/XML DOM parser with CSS selectors</p> <h1 id="SYNOPSIS"><a class="permalink" href="#SYNOPSIS">#</a><a href="#toc">SYNOPSIS</a></h1> <pre><code>use Mojo::DOM; # Parse my $dom = Mojo::DOM->new('<div><p id="a">Test</p><p id="b">123</p></div>'); # Find say $dom->at('#b')->text; say $dom->find('p')->map('text')->join("\n"); say $dom->find('[id]')->map(attr => 'id')->join("\n"); # Iterate $dom->find('p[id]')->reverse->each(sub { say $_->{id} }); # Loop for my $e ($dom->find('p[id]')->each) { say $e->{id}, ':', $e->text; } # Modify $dom->find('div p')->last->append('<p id="c">456</p>'); $dom->at('#c')->prepend($dom->new_tag('p', id => 'd', '789')); $dom->find(':not(p)')->map('strip'); # Render say "$dom";</code></pre> <h1 id="DESCRIPTION"><a class="permalink" href="#DESCRIPTION">#</a><a href="#toc">DESCRIPTION</a></h1> <p><a href="http://docs.mojolicious.org/Mojo/DOM">Mojo::DOM</a> is a minimalistic and relaxed HTML/XML DOM parser with CSS selector support. It will even try to interpret broken HTML and XML, so you should not use it for validation.</p> <h1 id="NODES-AND-ELEMENTS"><a class="permalink" href="#NODES-AND-ELEMENTS">#</a><a href="#toc">NODES AND ELEMENTS</a></h1> <p>When we parse an HTML/XML fragment, it gets turned into a tree of nodes.</p> <pre><code><!DOCTYPE html> <html> <head><title>Hello</title></head> <body>World!</body> </html></code></pre> <p>There are currently eight different kinds of nodes, <code>cdata</code>, <code>comment</code>, <code>doctype</code>, <code>pi</code>, <code>raw</code>, <code>root</code>, <code>tag</code> and <code>text</code>. Elements are nodes of the type <code>tag</code>.</p> <pre><code class="nohighlight">root |- doctype (html) +- tag (html) |- tag (head) | +- tag (title) | +- raw (Hello) +- tag (body) +- text (World!)</code></pre> <p>While all node types are represented as <a href="http://docs.mojolicious.org/Mojo/DOM">Mojo::DOM</a> objects, some methods like <a href="#attr">"attr"</a> and <a href="#namespace">"namespace"</a> only apply to elements.</p> <h1 id="HTML-AND-XML"><a class="permalink" href="#HTML-AND-XML">#</a><a href="#toc">HTML AND XML</a></h1> <p><a href="http://docs.mojolicious.org/Mojo/DOM">Mojo::DOM</a> defaults to HTML semantics, that means all tags and attribute names are lowercased and selectors need to be lowercase as well.</p> <pre><code># HTML semantics my $dom = Mojo::DOM->new('<P ID="greeting">Hi!</P>'); say $dom->at('p[id]')->text;</code></pre> <p>If an XML declaration is found, the parser will automatically switch into XML mode and everything becomes case-sensitive.</p> <pre><code># XML semantics my $dom = Mojo::DOM->new('<?xml version="1.0"?><P ID="greeting">Hi!</P>'); say $dom->at('P[ID]')->text;</code></pre> <p>HTML or XML semantics can also be forced with the <a href="#xml">"xml"</a> method.</p> <pre><code># Force HTML semantics my $dom = Mojo::DOM->new->xml(0)->parse('<P ID="greeting">Hi!</P>'); say $dom->at('p[id]')->text; # Force XML semantics my $dom = Mojo::DOM->new->xml(1)->parse('<P ID="greeting">Hi!</P>'); say $dom->at('P[ID]')->text;</code></pre> <h1 id="METHODS"><a class="permalink" href="#METHODS">#</a><a href="#toc">METHODS</a></h1> <p><a href="http://docs.mojolicious.org/Mojo/DOM">Mojo::DOM</a> implements the following methods.</p> <h2 id="all_text"><a class="permalink" href="#all_text">#</a><a href="#toc">all_text</a></h2> <pre><code>my $text = $dom->all_text;</code></pre> <p>Extract text content from all descendant nodes of this element. For HTML documents <code>script</code> and <code>style</code> elements are excluded.</p> <pre><code># "foo\nbarbaz\n" $dom->parse("<div>foo\n<p>bar</p>baz\n</div>")->at('div')->all_text;</code></pre> <h2 id="ancestors"><a class="permalink" href="#ancestors">#</a><a href="#toc">ancestors</a></h2> <pre><code>my $collection = $dom->ancestors; my $collection = $dom->ancestors('div ~ p');</code></pre> <p>Find all ancestor elements of this node matching the CSS selector and return a <a href="http://docs.mojolicious.org/Mojo/Collection">Mojo::Collection</a> object containing these elements as <a href="http://docs.mojolicious.org/Mojo/DOM">Mojo::DOM</a> objects. All selectors from <a href="http://docs.mojolicious.org/Mojo/DOM/CSS#SELECTORS">"SELECTORS" in Mojo::DOM::CSS</a> are supported.</p> <pre><code># List tag names of ancestor elements say $dom->ancestors->map('tag')->join("\n");</code></pre> <h2 id="append"><a class="permalink" href="#append">#</a><a href="#toc">append</a></h2> <pre><code>$dom = $dom->append('<p>I ♥ Mojolicious!</p>'); $dom = $dom->append(Mojo::DOM->new);</code></pre> <p>Append HTML/XML fragment to this node (for all node types other than <code>root</code>).</p> <pre><code># "<div><h1>Test</h1><h2>123</h2></div>" $dom->parse('<div><h1>Test</h1></div>') ->at('h1')->append('<h2>123</h2>')->root; # "<p>Test 123</p>" $dom->parse('<p>Test</p>')->at('p') ->child_nodes->first->append(' 123')->root;</code></pre> <h2 id="append_content"><a class="permalink" href="#append_content">#</a><a href="#toc">append_content</a></h2> <pre><code>$dom = $dom->append_content('<p>I ♥ Mojolicious!</p>'); $dom = $dom->append_content(Mojo::DOM->new);</code></pre> <p>Append HTML/XML fragment (for <code>root</code> and <code>tag</code> nodes) or raw content to this node's content.</p> <pre><code># "<div><h1>Test123</h1></div>" $dom->parse('<div><h1>Test</h1></div>') ->at('h1')->append_content('123')->root; # "<!-- Test 123 --><br>" $dom->parse('<!-- Test --><br>') ->child_nodes->first->append_content('123 ')->root; # "<p>Test<i>123</i></p>" $dom->parse('<p>Test</p>')->at('p')->append_content('<i>123</i>')->root;</code></pre> <h2 id="at"><a class="permalink" href="#at">#</a><a href="#toc">at</a></h2> <pre><code>my $result = $dom->at('div ~ p'); my $result = $dom->at('svg|line', svg => 'http://www.w3.org/2000/svg');</code></pre> <p>Find first descendant element of this element matching the CSS selector and return it as a <a href="http://docs.mojolicious.org/Mojo/DOM">Mojo::DOM</a> object, or <code>undef</code> if none could be found. All selectors from <a href="http://docs.mojolicious.org/Mojo/DOM/CSS#SELECTORS">"SELECTORS" in Mojo::DOM::CSS</a> are supported.</p> <pre><code># Find first element with "svg" namespace definition my $namespace = $dom->at('[xmlns\:svg]')->{'xmlns:svg'};</code></pre> <p>Trailing key/value pairs can be used to declare xml namespace aliases.</p> <pre><code># "<rect />" $dom->parse('<svg xmlns="http://www.w3.org/2000/svg"><rect /></svg>') ->at('svg|rect', svg => 'http://www.w3.org/2000/svg');</code></pre> <h2 id="attr"><a class="permalink" href="#attr">#</a><a href="#toc">attr</a></h2> <pre><code>my $hash = $dom->attr; my $foo = $dom->attr('foo'); $dom = $dom->attr({foo => 'bar'}); $dom = $dom->attr(foo => 'bar');</code></pre> <p>This element's attributes.</p> <pre><code># Remove an attribute delete $dom->attr->{id}; # Attribute without value $dom->attr(selected => undef); # List id attributes say $dom->find('*')->map(attr => 'id')->compact->join("\n");</code></pre> <h2 id="child_nodes"><a class="permalink" href="#child_nodes">#</a><a href="#toc">child_nodes</a></h2> <pre><code>my $collection = $dom->child_nodes;</code></pre> <p>Return a <a href="http://docs.mojolicious.org/Mojo/Collection">Mojo::Collection</a> object containing all child nodes of this element as <a href="http://docs.mojolicious.org/Mojo/DOM">Mojo::DOM</a> objects.</p> <pre><code># "<p><b>123</b></p>" $dom->parse('<p>Test<b>123</b></p>')->at('p')->child_nodes->first->remove; # "<!DOCTYPE html>" $dom->parse('<!DOCTYPE html><b>123</b>')->child_nodes->first; # " Test " $dom->parse('<b>123</b><!-- Test -->')->child_nodes->last->content;</code></pre> <h2 id="children"><a class="permalink" href="#children">#</a><a href="#toc">children</a></h2> <pre><code>my $collection = $dom->children; my $collection = $dom->children('div ~ p');</code></pre> <p>Find all child elements of this element matching the CSS selector and return a <a href="http://docs.mojolicious.org/Mojo/Collection">Mojo::Collection</a> object containing these elements as <a href="http://docs.mojolicious.org/Mojo/DOM">Mojo::DOM</a> objects. All selectors from <a href="http://docs.mojolicious.org/Mojo/DOM/CSS#SELECTORS">"SELECTORS" in Mojo::DOM::CSS</a> are supported.</p> <pre><code># Show tag name of random child element say $dom->children->shuffle->first->tag;</code></pre> <h2 id="content"><a class="permalink" href="#content">#</a><a href="#toc">content</a></h2> <pre><code>my $str = $dom->content; $dom = $dom->content('<p>I ♥ Mojolicious!</p>'); $dom = $dom->content(Mojo::DOM->new);</code></pre> <p>Return this node's content or replace it with HTML/XML fragment (for <code>root</code> and <code>tag</code> nodes) or raw content.</p> <pre><code># "<b>Test</b>" $dom->parse('<div><b>Test</b></div>')->at('div')->content; # "<div><h1>123</h1></div>" $dom->parse('<div><h1>Test</h1></div>')->at('h1')->content('123')->root; # "<p><i>123</i></p>" $dom->parse('<p>Test</p>')->at('p')->content('<i>123</i>')->root; # "<div><h1></h1></div>" $dom->parse('<div><h1>Test</h1></div>')->at('h1')->content('')->root; # " Test " $dom->parse('<!-- Test --><br>')->child_nodes->first->content; # "<div><!-- 123 -->456</div>" $dom->parse('<div><!-- Test -->456</div>') ->at('div')->child_nodes->first->content(' 123 ')->root;</code></pre> <h2 id="descendant_nodes"><a class="permalink" href="#descendant_nodes">#</a><a href="#toc">descendant_nodes</a></h2> <pre><code>my $collection = $dom->descendant_nodes;</code></pre> <p>Return a <a href="http://docs.mojolicious.org/Mojo/Collection">Mojo::Collection</a> object containing all descendant nodes of this element as <a href="http://docs.mojolicious.org/Mojo/DOM">Mojo::DOM</a> objects.</p> <pre><code># "<p><b>123</b></p>" $dom->parse('<p><!-- Test --><b>123<!-- 456 --></b></p>') ->descendant_nodes->grep(sub { $_->type eq 'comment' }) ->map('remove')->first; # "<p><b>test</b>test</p>" $dom->parse('<p><b>123</b>456</p>') ->at('p')->descendant_nodes->grep(sub { $_->type eq 'text' }) ->map(content => 'test')->first->root;</code></pre> <h2 id="find"><a class="permalink" href="#find">#</a><a href="#toc">find</a></h2> <pre><code>my $collection = $dom->find('div ~ p'); my $collection = $dom->find('svg|line', svg => 'http://www.w3.org/2000/svg');</code></pre> <p>Find all descendant elements of this element matching the CSS selector and return a <a href="http://docs.mojolicious.org/Mojo/Collection">Mojo::Collection</a> object containing these elements as <a href="http://docs.mojolicious.org/Mojo/DOM">Mojo::DOM</a> objects. All selectors from <a href="http://docs.mojolicious.org/Mojo/DOM/CSS#SELECTORS">"SELECTORS" in Mojo::DOM::CSS</a> are supported.</p> <pre><code># Find a specific element and extract information my $id = $dom->find('div')->[23]{id}; # Extract information from multiple elements my @headers = $dom->find('h1, h2, h3')->map('text')->each; # Count all the different tags my $hash = $dom->find('*')->reduce(sub { $a->{$b->tag}++; $a }, {}); # Find elements with a class that contains dots my @divs = $dom->find('div.foo\.bar')->each;</code></pre> <p>Trailing key/value pairs can be used to declare xml namespace aliases.</p> <pre><code># "<rect />" $dom->parse('<svg xmlns="http://www.w3.org/2000/svg"><rect /></svg>') ->find('svg|rect', svg => 'http://www.w3.org/2000/svg')->first;</code></pre> <h2 id="following"><a class="permalink" href="#following">#</a><a href="#toc">following</a></h2> <pre><code>my $collection = $dom->following; my $collection = $dom->following('div ~ p');</code></pre> <p>Find all sibling elements after this node matching the CSS selector and return a <a href="http://docs.mojolicious.org/Mojo/Collection">Mojo::Collection</a> object containing these elements as <a href="http://docs.mojolicious.org/Mojo/DOM">Mojo::DOM</a> objects. All selectors from <a href="http://docs.mojolicious.org/Mojo/DOM/CSS#SELECTORS">"SELECTORS" in Mojo::DOM::CSS</a> are supported.</p> <pre><code># List tags of sibling elements after this node say $dom->following->map('tag')->join("\n");</code></pre> <h2 id="following_nodes"><a class="permalink" href="#following_nodes">#</a><a href="#toc">following_nodes</a></h2> <pre><code>my $collection = $dom->following_nodes;</code></pre> <p>Return a <a href="http://docs.mojolicious.org/Mojo/Collection">Mojo::Collection</a> object containing all sibling nodes after this node as <a href="http://docs.mojolicious.org/Mojo/DOM">Mojo::DOM</a> objects.</p> <pre><code># "C" $dom->parse('<p>A</p><!-- B -->C')->at('p')->following_nodes->last->content;</code></pre> <h2 id="matches"><a class="permalink" href="#matches">#</a><a href="#toc">matches</a></h2> <pre><code>my $bool = $dom->matches('div ~ p'); my $bool = $dom->matches('svg|line', svg => 'http://www.w3.org/2000/svg');</code></pre> <p>Check if this element matches the CSS selector. All selectors from <a href="http://docs.mojolicious.org/Mojo/DOM/CSS#SELECTORS">"SELECTORS" in Mojo::DOM::CSS</a> are supported.</p> <pre><code># True $dom->parse('<p class="a">A</p>')->at('p')->matches('.a'); $dom->parse('<p class="a">A</p>')->at('p')->matches('p[class]'); # False $dom->parse('<p class="a">A</p>')->at('p')->matches('.b'); $dom->parse('<p class="a">A</p>')->at('p')->matches('p[id]');</code></pre> <p>Trailing key/value pairs can be used to declare xml namespace aliases.</p> <pre><code># True $dom->parse('<svg xmlns="http://www.w3.org/2000/svg"><rect /></svg>') ->matches('svg|rect', svg => 'http://www.w3.org/2000/svg');</code></pre> <h2 id="namespace"><a class="permalink" href="#namespace">#</a><a href="#toc">namespace</a></h2> <pre><code>my $namespace = $dom->namespace;</code></pre> <p>Find this element's namespace, or return <code>undef</code> if none could be found.</p> <pre><code># "http://www.w3.org/2000/svg" Mojo::DOM->new('<svg xmlns:svg="http://www.w3.org/2000/svg"><svg:circle>3.14</svg:circle></svg>')->at('svg\:circle')->namespace; # Find namespace for an element with namespace prefix my $namespace = $dom->at('svg > svg\:circle')->namespace; # Find namespace for an element that may or may not have a namespace prefix my $namespace = $dom->at('svg > circle')->namespace;</code></pre> <h2 id="new"><a class="permalink" href="#new">#</a><a href="#toc">new</a></h2> <pre><code>my $dom = Mojo::DOM->new; my $dom = Mojo::DOM->new('<foo bar="baz">I ♥ Mojolicious!</foo>');</code></pre> <p>Construct a new scalar-based <a href="http://docs.mojolicious.org/Mojo/DOM">Mojo::DOM</a> object and <a href="#parse">"parse"</a> HTML/XML fragment if necessary.</p> <h2 id="new_tag"><a class="permalink" href="#new_tag">#</a><a href="#toc">new_tag</a></h2> <pre><code>my $tag = Mojo::DOM->new_tag('div'); my $tag = $dom->new_tag('div'); my $tag = $dom->new_tag('div', id => 'foo', hidden => undef); my $tag = $dom->new_tag('div', 'safe content'); my $tag = $dom->new_tag('div', id => 'foo', 'safe content'); my $tag = $dom->new_tag('div', data => {mojo => 'rocks'}, 'safe content'); my $tag = $dom->new_tag('div', id => 'foo', sub { 'unsafe content' });</code></pre> <p>Construct a new <a href="http://docs.mojolicious.org/Mojo/DOM">Mojo::DOM</a> object for an HTML/XML tag with or without attributes and content. The <code>data</code> attribute may contain a hash reference with key/value pairs to generate attributes from.</p> <pre><code># "<br>" $dom->new_tag('br'); # "<div></div>" $dom->new_tag('div'); # "<div id="foo" hidden></div>" $dom->new_tag('div', id => 'foo', hidden => undef); # "<div>test &amp; 123</div>" $dom->new_tag('div', 'test & 123'); # "<div id="foo">test &amp; 123</div>" $dom->new_tag('div', id => 'foo', 'test & 123'); # "<div data-foo="1" data-bar="test">test &amp; 123</div>"" $dom->new_tag('div', data => {foo => 1, Bar => 'test'}, 'test & 123'); # "<div id="foo">test & 123</div>" $dom->new_tag('div', id => 'foo', sub { 'test & 123' }); # "<div>Hello<b>Mojo!</b></div>" $dom->parse('<div>Hello</div>')->at('div') ->append_content($dom->new_tag('b', 'Mojo!'))->root;</code></pre> <h2 id="next"><a class="permalink" href="#next">#</a><a href="#toc">next</a></h2> <pre><code>my $sibling = $dom->next;</code></pre> <p>Return <a href="http://docs.mojolicious.org/Mojo/DOM">Mojo::DOM</a> object for next sibling element, or <code>undef</code> if there are no more siblings.</p> <pre><code># "<h2>123</h2>" $dom->parse('<div><h1>Test</h1><h2>123</h2></div>')->at('h1')->next;</code></pre> <h2 id="next_node"><a class="permalink" href="#next_node">#</a><a href="#toc">next_node</a></h2> <pre><code>my $sibling = $dom->next_node;</code></pre> <p>Return <a href="http://docs.mojolicious.org/Mojo/DOM">Mojo::DOM</a> object for next sibling node, or <code>undef</code> if there are no more siblings.</p> <pre><code># "456" $dom->parse('<p><b>123</b><!-- Test -->456</p>') ->at('b')->next_node->next_node; # " Test " $dom->parse('<p><b>123</b><!-- Test -->456</p>') ->at('b')->next_node->content;</code></pre> <h2 id="parent"><a class="permalink" href="#parent">#</a><a href="#toc">parent</a></h2> <pre><code>my $parent = $dom->parent;</code></pre> <p>Return <a href="http://docs.mojolicious.org/Mojo/DOM">Mojo::DOM</a> object for parent of this node, or <code>undef</code> if this node has no parent.</p> <pre><code># "<b><i>Test</i></b>" $dom->parse('<p><b><i>Test</i></b></p>')->at('i')->parent;</code></pre> <h2 id="parse"><a class="permalink" href="#parse">#</a><a href="#toc">parse</a></h2> <pre><code>$dom = $dom->parse('<foo bar="baz">I ♥ Mojolicious!</foo>');</code></pre> <p>Parse HTML/XML fragment with <a href="http://docs.mojolicious.org/Mojo/DOM/HTML">Mojo::DOM::HTML</a>.</p> <pre><code># Parse XML my $dom = Mojo::DOM->new->xml(1)->parse('<foo>I ♥ Mojolicious!</foo>');</code></pre> <h2 id="preceding"><a class="permalink" href="#preceding">#</a><a href="#toc">preceding</a></h2> <pre><code>my $collection = $dom->preceding; my $collection = $dom->preceding('div ~ p');</code></pre> <p>Find all sibling elements before this node matching the CSS selector and return a <a href="http://docs.mojolicious.org/Mojo/Collection">Mojo::Collection</a> object containing these elements as <a href="http://docs.mojolicious.org/Mojo/DOM">Mojo::DOM</a> objects. All selectors from <a href="http://docs.mojolicious.org/Mojo/DOM/CSS#SELECTORS">"SELECTORS" in Mojo::DOM::CSS</a> are supported.</p> <pre><code># List tags of sibling elements before this node say $dom->preceding->map('tag')->join("\n");</code></pre> <h2 id="preceding_nodes"><a class="permalink" href="#preceding_nodes">#</a><a href="#toc">preceding_nodes</a></h2> <pre><code>my $collection = $dom->preceding_nodes;</code></pre> <p>Return a <a href="http://docs.mojolicious.org/Mojo/Collection">Mojo::Collection</a> object containing all sibling nodes before this node as <a href="http://docs.mojolicious.org/Mojo/DOM">Mojo::DOM</a> objects.</p> <pre><code># "A" $dom->parse('A<!-- B --><p>C</p>')->at('p')->preceding_nodes->first->content;</code></pre> <h2 id="prepend"><a class="permalink" href="#prepend">#</a><a href="#toc">prepend</a></h2> <pre><code>$dom = $dom->prepend('<p>I ♥ Mojolicious!</p>'); $dom = $dom->prepend(Mojo::DOM->new);</code></pre> <p>Prepend HTML/XML fragment to this node (for all node types other than <code>root</code>).</p> <pre><code># "<div><h1>Test</h1><h2>123</h2></div>" $dom->parse('<div><h2>123</h2></div>') ->at('h2')->prepend('<h1>Test</h1>')->root; # "<p>Test 123</p>" $dom->parse('<p>123</p>') ->at('p')->child_nodes->first->prepend('Test ')->root;</code></pre> <h2 id="prepend_content"><a class="permalink" href="#prepend_content">#</a><a href="#toc">prepend_content</a></h2> <pre><code>$dom = $dom->prepend_content('<p>I ♥ Mojolicious!</p>'); $dom = $dom->prepend_content(Mojo::DOM->new);</code></pre> <p>Prepend HTML/XML fragment (for <code>root</code> and <code>tag</code> nodes) or raw content to this node's content.</p> <pre><code># "<div><h2>Test123</h2></div>" $dom->parse('<div><h2>123</h2></div>') ->at('h2')->prepend_content('Test')->root; # "<!-- Test 123 --><br>" $dom->parse('<!-- 123 --><br>') ->child_nodes->first->prepend_content(' Test')->root; # "<p><i>123</i>Test</p>" $dom->parse('<p>Test</p>')->at('p')->prepend_content('<i>123</i>')->root;</code></pre> <h2 id="previous"><a class="permalink" href="#previous">#</a><a href="#toc">previous</a></h2> <pre><code>my $sibling = $dom->previous;</code></pre> <p>Return <a href="http://docs.mojolicious.org/Mojo/DOM">Mojo::DOM</a> object for previous sibling element, or <code>undef</code> if there are no more siblings.</p> <pre><code># "<h1>Test</h1>" $dom->parse('<div><h1>Test</h1><h2>123</h2></div>')->at('h2')->previous;</code></pre> <h2 id="previous_node"><a class="permalink" href="#previous_node">#</a><a href="#toc">previous_node</a></h2> <pre><code>my $sibling = $dom->previous_node;</code></pre> <p>Return <a href="http://docs.mojolicious.org/Mojo/DOM">Mojo::DOM</a> object for previous sibling node, or <code>undef</code> if there are no more siblings.</p> <pre><code># "123" $dom->parse('<p>123<!-- Test --><b>456</b></p>') ->at('b')->previous_node->previous_node; # " Test " $dom->parse('<p>123<!-- Test --><b>456</b></p>') ->at('b')->previous_node->content;</code></pre> <h2 id="remove"><a class="permalink" href="#remove">#</a><a href="#toc">remove</a></h2> <pre><code>my $parent = $dom->remove;</code></pre> <p>Remove this node and return <a href="#root">"root"</a> (for <code>root</code> nodes) or <a href="#parent">"parent"</a>.</p> <pre><code># "<div></div>" $dom->parse('<div><h1>Test</h1></div>')->at('h1')->remove; # "<p><b>456</b></p>" $dom->parse('<p>123<b>456</b></p>') ->at('p')->child_nodes->first->remove->root;</code></pre> <h2 id="replace"><a class="permalink" href="#replace">#</a><a href="#toc">replace</a></h2> <pre><code>my $parent = $dom->replace('<div>I ♥ Mojolicious!</div>'); my $parent = $dom->replace(Mojo::DOM->new);</code></pre> <p>Replace this node with HTML/XML fragment and return <a href="#root">"root"</a> (for <code>root</code> nodes) or <a href="#parent">"parent"</a>.</p> <pre><code># "<div><h2>123</h2></div>" $dom->parse('<div><h1>Test</h1></div>')->at('h1')->replace('<h2>123</h2>'); # "<p><b>123</b></p>" $dom->parse('<p>Test</p>') ->at('p')->child_nodes->[0]->replace('<b>123</b>')->root;</code></pre> <h2 id="root"><a class="permalink" href="#root">#</a><a href="#toc">root</a></h2> <pre><code>my $root = $dom->root;</code></pre> <p>Return <a href="http://docs.mojolicious.org/Mojo/DOM">Mojo::DOM</a> object for <code>root</code> node.</p> <h2 id="selector"><a class="permalink" href="#selector">#</a><a href="#toc">selector</a></h2> <pre><code>my $selector = $dom->selector;</code></pre> <p>Get a unique CSS selector for this element.</p> <pre><code># "ul:nth-child(1) > li:nth-child(2)" $dom->parse('<ul><li>Test</li><li>123</li></ul>')->find('li')->last->selector; # "p:nth-child(1) > b:nth-child(1) > i:nth-child(1)" $dom->parse('<p><b><i>Test</i></b></p>')->at('i')->selector;</code></pre> <h2 id="strip"><a class="permalink" href="#strip">#</a><a href="#toc">strip</a></h2> <pre><code>my $parent = $dom->strip;</code></pre> <p>Remove this element while preserving its content and return <a href="#parent">"parent"</a>.</p> <pre><code># "<div>Test</div>" $dom->parse('<div><h1>Test</h1></div>')->at('h1')->strip;</code></pre> <h2 id="tag"><a class="permalink" href="#tag">#</a><a href="#toc">tag</a></h2> <pre><code>my $tag = $dom->tag; $dom = $dom->tag('div');</code></pre> <p>This element's tag name.</p> <pre><code># List tag names of child elements say $dom->children->map('tag')->join("\n");</code></pre> <h2 id="tap"><a class="permalink" href="#tap">#</a><a href="#toc">tap</a></h2> <pre><code>$dom = $dom->tap(sub {...});</code></pre> <p>Alias for <a href="http://docs.mojolicious.org/Mojo/Base#tap">"tap" in Mojo::Base</a>.</p> <h2 id="text"><a class="permalink" href="#text">#</a><a href="#toc">text</a></h2> <pre><code>my $text = $dom->text;</code></pre> <p>Extract text content from this element only (not including child elements).</p> <pre><code># "bar" $dom->parse("<div>foo<p>bar</p>baz</div>")->at('p')->text; # "foo\nbaz\n" $dom->parse("<div>foo\n<p>bar</p>baz\n</div>")->at('div')->text;</code></pre> <p>To extract text content from all descendant nodes see <a href="#all_text">"all_text"</a>.</p> <h2 id="to_string"><a class="permalink" href="#to_string">#</a><a href="#toc">to_string</a></h2> <pre><code>my $str = $dom->to_string;</code></pre> <p>Render this node and its content to HTML/XML.</p> <pre><code># "<b>Test</b>" $dom->parse('<div><b>Test</b></div>')->at('div b')->to_string;</code></pre> <h2 id="tree"><a class="permalink" href="#tree">#</a><a href="#toc">tree</a></h2> <pre><code>my $tree = $dom->tree; $dom = $dom->tree(['root']);</code></pre> <p>Document Object Model. Note that this structure should only be used very carefully since it is very dynamic.</p> <h2 id="type"><a class="permalink" href="#type">#</a><a href="#toc">type</a></h2> <pre><code>my $type = $dom->type;</code></pre> <p>This node's type, usually <code>cdata</code>, <code>comment</code>, <code>doctype</code>, <code>pi</code>, <code>raw</code>, <code>root</code>, <code>tag</code> or <code>text</code>.</p> <pre><code># "cdata" $dom->parse('<![CDATA[Test]]>')->child_nodes->first->type; # "comment" $dom->parse('<!-- Test -->')->child_nodes->first->type; # "doctype" $dom->parse('<!DOCTYPE html>')->child_nodes->first->type; # "pi" $dom->parse('<?xml version="1.0"?>')->child_nodes->first->type; # "raw" $dom->parse('<title>Test</title>')->at('title')->child_nodes->first->type; # "root" $dom->parse('<p>Test</p>')->type; # "tag" $dom->parse('<p>Test</p>')->at('p')->type; # "text" $dom->parse('<p>Test</p>')->at('p')->child_nodes->first->type;</code></pre> <h2 id="val"><a class="permalink" href="#val">#</a><a href="#toc">val</a></h2> <pre><code>my $value = $dom->val;</code></pre> <p>Extract value from form element (such as <code>button</code>, <code>input</code>, <code>option</code>, <code>select</code> and <code>textarea</code>), or return <code>undef</code> if this element has no value. In the case of <code>select</code> with <code>multiple</code> attribute, find <code>option</code> elements with <code>selected</code> attribute and return an array reference with all values, or <code>undef</code> if none could be found.</p> <pre><code># "a" $dom->parse('<input name=test value=a>')->at('input')->val; # "b" $dom->parse('<textarea>b</textarea>')->at('textarea')->val; # "c" $dom->parse('<option value="c">Test</option>')->at('option')->val; # "d" $dom->parse('<select><option selected>d</option></select>') ->at('select')->val; # "e" $dom->parse('<select multiple><option selected>e</option></select>') ->at('select')->val->[0]; # "on" $dom->parse('<input name=test type=checkbox>')->at('input')->val;</code></pre> <h2 id="with_roles"><a class="permalink" href="#with_roles">#</a><a href="#toc">with_roles</a></h2> <pre><code>my $new_class = Mojo::DOM->with_roles('Mojo::DOM::Role::One'); my $new_class = Mojo::DOM->with_roles('+One', '+Two'); $dom = $dom->with_roles('+One', '+Two');</code></pre> <p>Alias for <a href="http://docs.mojolicious.org/Mojo/Base#with_roles">"with_roles" in Mojo::Base</a>.</p> <h2 id="wrap"><a class="permalink" href="#wrap">#</a><a href="#toc">wrap</a></h2> <pre><code>$dom = $dom->wrap('<div></div>'); $dom = $dom->wrap(Mojo::DOM->new);</code></pre> <p>Wrap HTML/XML fragment around this node (for all node types other than <code>root</code>), placing it as the last child of the first innermost element.</p> <pre><code># "<p>123<b>Test</b></p>" $dom->parse('<b>Test</b>')->at('b')->wrap('<p>123</p>')->root; # "<div><p><b>Test</b></p>123</div>" $dom->parse('<b>Test</b>')->at('b')->wrap('<div><p></p>123</div>')->root; # "<p><b>Test</b></p><p>123</p>" $dom->parse('<b>Test</b>')->at('b')->wrap('<p></p><p>123</p>')->root; # "<p><b>Test</b></p>" $dom->parse('<p>Test</p>')->at('p')->child_nodes->first->wrap('<b>')->root;</code></pre> <h2 id="wrap_content"><a class="permalink" href="#wrap_content">#</a><a href="#toc">wrap_content</a></h2> <pre><code>$dom = $dom->wrap_content('<div></div>'); $dom = $dom->wrap_content(Mojo::DOM->new);</code></pre> <p>Wrap HTML/XML fragment around this node's content (for <code>root</code> and <code>tag</code> nodes), placing it as the last children of the first innermost element.</p> <pre><code># "<p><b>123Test</b></p>" $dom->parse('<p>Test<p>')->at('p')->wrap_content('<b>123</b>')->root; # "<p><b>Test</b></p><p>123</p>" $dom->parse('<b>Test</b>')->wrap_content('<p></p><p>123</p>');</code></pre> <h2 id="xml"><a class="permalink" href="#xml">#</a><a href="#toc">xml</a></h2> <pre><code>my $bool = $dom->xml; $dom = $dom->xml($bool);</code></pre> <p>Disable HTML semantics in parser and activate case-sensitivity, defaults to auto-detection based on XML declarations.</p> <h1 id="OPERATORS"><a class="permalink" href="#OPERATORS">#</a><a href="#toc">OPERATORS</a></h1> <p><a href="http://docs.mojolicious.org/Mojo/DOM">Mojo::DOM</a> overloads the following operators.</p> <h2 id="array"><a class="permalink" href="#array">#</a><a href="#toc">array</a></h2> <pre><code>my @nodes = @$dom;</code></pre> <p>Alias for <a href="#child_nodes">"child_nodes"</a>.</p> <pre><code># "<!-- Test -->" $dom->parse('<!-- Test --><b>123</b>')->[0];</code></pre> <h2 id="bool"><a class="permalink" href="#bool">#</a><a href="#toc">bool</a></h2> <pre><code>my $bool = !!$dom;</code></pre> <p>Always true.</p> <h2 id="hash"><a class="permalink" href="#hash">#</a><a href="#toc">hash</a></h2> <pre><code>my %attrs = %$dom;</code></pre> <p>Alias for <a href="#attr">"attr"</a>.</p> <pre><code># "test" $dom->parse('<div id="test">Test</div>')->at('div')->{id};</code></pre> <h2 id="stringify"><a class="permalink" href="#stringify">#</a><a href="#toc">stringify</a></h2> <pre><code>my $str = "$dom";</code></pre> <p>Alias for <a href="#to_string">"to_string"</a>.</p> <h1 id="SEE-ALSO"><a class="permalink" href="#SEE-ALSO">#</a><a href="#toc">SEE ALSO</a></h1> <p><a href="http://docs.mojolicious.org/Mojolicious">Mojolicious</a>, <a href="http://docs.mojolicious.org/Mojolicious/Guides">Mojolicious::Guides</a>, <a href="https://mojolicious.org">https://mojolicious.org</a>.</p> </div> </main> </div> </div> <footer> <div class="container-fluid p-3 mojo-footer"> <div class="row"> <div class="col-sm align-self-center text-center mojo-free"> <b>Free</b> and <b>Open Source</b>. </div> <div class="col-sm align-self-center text-center mojo-copy"> <i class="far fa-copyright"></i> 2008-2023 Sebastian Riedel and the <a href="https://docs.mojolicious.org/Mojolicious#AUTHORS">Mojolicious contributors</a>. </div> <div class="col-sm align-self-center text-center mojo-social"> <a alt="GitHub" href="https://github.com/mojolicious/mojo"><i class="fab fa-github-alt"></i></a> <a alt="Mastodon" rel="me" href="https://fosstodon.org/@mojolicious"><i class="fab fa-mastodon"></i></a> <a alt="LinkedIn" href="https://www.linkedin.com/groups/8963713/"><i class="fab fa-linkedin"></i></a> </div> </div> </div> </footer> <script> const links = document.querySelectorAll('.mojo-sidebar ul li a[href^="#"]'); const linkById = Object.fromEntries(Array.from(links).map(e => [e.getAttribute('href').substr(1), e])); const sections = Array.from(links).map(e => document.getElementById(e.getAttribute('href').substr(1))).reverse(); let lastSectionId; let mojoOnScroll = () => { const pos = (document.documentElement.scrollTop || document.body.scrollTop) - 63; const section = sections.find(e => e.offsetTop <= pos); if (!section) return; if (section.id == lastSectionId) return; lastSectionId = section.id; links.forEach(e => e.classList.remove('font-weight-bold')); linkById[section.id].classList.add('font-weight-bold'); }; window.onscroll = mojoOnScroll; mojoOnScroll(); </script> </body> </html>