Skip to content

Commit

Permalink
added Mojo::DOM::Node
Browse files Browse the repository at this point in the history
  • Loading branch information
kraih committed Jan 19, 2014
1 parent f00a449 commit 4845b78
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 3 deletions.
2 changes: 2 additions & 0 deletions Changes
@@ -1,5 +1,7 @@

4.68 2014-01-19
- Added Mojo::DOM::Node.
- Added contents and node methods to Mojo::DOM.
- Removed deprecated http_proxy attribute from Mojo::UserAgent.
- Removed deprecated https_proxy attribute from Mojo::UserAgent.
- Removed deprecated name attribute from Mojo::UserAgent.
Expand Down
33 changes: 30 additions & 3 deletions lib/Mojo/DOM.pm
Expand Up @@ -12,6 +12,7 @@ use Carp 'croak';
use Mojo::Collection;
use Mojo::DOM::CSS;
use Mojo::DOM::HTML;
use Mojo::DOM::Node;
use Mojo::Util 'squish';
use Scalar::Util qw(blessed weaken);

Expand Down Expand Up @@ -84,6 +85,8 @@ sub content_xml {
return join '', map { _render($_, $xml) } _nodes($self->tree);
}

sub contents { $_[0]->_collect(_nodes($_[0]->tree)) }

sub find { $_[0]->_collect(@{$_[0]->_css->select($_[1])}) }

sub match { $_[0]->_css->match($_[1]) ? $_[0] : undef }
Expand Down Expand Up @@ -112,6 +115,8 @@ sub namespace {

sub next { shift->_siblings->[1][0] }

sub node { shift->tree->[0] }

sub parent {
my $self = shift;
return undef if (my $tree = $self->tree)->[0] eq 'root';
Expand Down Expand Up @@ -231,9 +236,15 @@ sub _ancestors {

sub _collect {
my $self = shift;
my $xml = $self->xml;
return Mojo::Collection->new(@_)
->map(sub { $self->new->tree($_)->xml($xml) });

my $xml = $self->xml;
return Mojo::Collection->new(@_)->map(
sub {
$_->[0] eq 'tag'
? $self->new->tree($_)->xml($xml)
: Mojo::DOM::Node->new(parent => $self, tree => $_);
}
);
}

sub _content {
Expand Down Expand Up @@ -530,6 +541,16 @@ Render content of this element to XML.
# "<b>test</b>"
$dom->parse('<div><b>test</b></div>')->div->content_xml;
=head2 contents
my $collection = $dom->contents;
Return a L<Mojo::Collection> object containing the children of this element as
L<Mojo::DOM> and L<Mojo::DOM::Node> objects.
"<p><b>123</b></p>"
$dom->parse('<p>test<b>123</b></p>')->at('p')->contents->first->remove;
=head2 find
my $collection = $dom->find('html title');
Expand Down Expand Up @@ -575,6 +596,12 @@ are no more siblings.
# "<h2>B</h2>"
$dom->parse('<div><h1>A</h1><h2>B</h2></div>')->at('h1')->next;
=head2 node
my $type = $dom->node;
Node type, usually C<root> or C<tag>.
=head2 parent
my $parent = $dom->parent;
Expand Down
95 changes: 95 additions & 0 deletions lib/Mojo/DOM/Node.pm
@@ -0,0 +1,95 @@
package Mojo::DOM::Node;
use Mojo::Base -base;
use overload bool => sub {1}, '""' => sub { shift->value }, fallback => 1;

has [qw(parent tree)];

sub node { shift->tree->[0] }

sub remove {
my $self = shift;

my $parent = $self->parent;
my $tree = $parent->tree;
my $node = $self->tree;
$tree->[$_] eq $node and splice(@$tree, $_, 1) and last
for ($tree->[0] eq 'root' ? 1 : 4) .. $#$tree;

return $parent;
}

sub value {
my $self = shift;
return $self->tree->[1] unless @_;
$self->tree->[1] = shift;
return $self;
}

1;

=encoding utf8
=head1 NAME
Mojo::DOM::Node - DOM Node
=head1 SYNOPSIS
use Mojo::DOM::Node;
my $node = Mojo::DOM::Node->new(parent => $parent, tree => $tree);
say $node->value;
=head1 DESCRIPTION
L<Mojo::DOM::Node> is a container for nodes used by L<Mojo::DOM>.
=head1 ATTRIBUTES
L<Mojo::DOM::Node> implements the following attributes.
=head2 parent
my $parent = $node->parent;
$node = $node->parent(Mojo::DOM->new);
Return L<Mojo::DOM> object for parent of this node.
=head2 tree
my $tree = $node->tree;
$node = $node->tree(['text', 'foo']);
Document Object Model. Note that this structure should only be used very
carefully since it is very dynamic.
=head1 METHODS
L<Mojo::DOM::Node> inherits all methods from L<Mojo::Base> and implements the
following new ones.
=head2 node
my $type = $node->node;
Node type, usually C<cdata>, C<comment>, C<doctype>, C<pi>, C<raw> or C<text>.
=head2 remove
my $parent = $node->remove;
Remove node and return L<Mojo::DOM> object for parent of node.
=head2 value
my $value = $node->value;
$node = $node->value('foo');
my $value = "$node";
Node value.
=head1 SEE ALSO
L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>.
=cut
26 changes: 26 additions & 0 deletions t/mojo/dom.t
Expand Up @@ -142,6 +142,32 @@ is_deeply [$dom->at('simple')->ancestors->type->each], ['foo'],
'right results';
ok !$dom->at('simple')->ancestors->first->xml, 'XML mode not active';

# Nodes
$dom = Mojo::DOM->new(
'<!DOCTYPE before><p>test<![CDATA[123]]><!-- 456 --></p><?after?>');
is $dom->contents->[1]->contents->first->parent->type, 'p', 'right type';
is $dom->contents->[1]->contents->first->value, 'test', 'right value';
is $dom->contents->[1]->contents->first, 'test', 'right value';
is $dom->at('p')->contents->first->node, 'text', 'right node';
is $dom->at('p')->contents->first->remove->type, 'p', 'right type';
is $dom->at('p')->contents->first->node, 'cdata', 'right node';
is $dom->at('p')->contents->first->value, '123', 'right value';
is $dom->at('p')->contents->[1]->node, 'comment', 'right node';
is $dom->at('p')->contents->[1]->value, ' 456 ', 'right value';
is $dom->contents->first->node, 'doctype', 'right node';
is $dom->contents->first->value, ' before', 'right value';
is $dom->contents->[2]->node, 'pi', 'right node';
is $dom->contents->[2]->value, 'after', 'right value';
is $dom->contents->first->value(' again')->value, ' again', 'right value';
is "$dom", '<!DOCTYPE again><p><![CDATA[123]]><!-- 456 --></p><?after?>',
'right result';
$dom = Mojo::DOM->new('<script>la<la>la</script>');
is $dom->node, 'root', 'right node';
is $dom->at('script')->node, 'tag', 'right node';
is $dom->at('script')->contents->first->node, 'raw', 'right node';
is $dom->at('script')->contents->first->value, 'la<la>la', 'right value';
is "$dom", '<script>la<la>la</script>', 'right result';

# Class and ID
$dom = Mojo::DOM->new->parse('<div id="id" class="class">a</div>');
is $dom->at('div#id.class')->text, 'a', 'right text';
Expand Down

0 comments on commit 4845b78

Please sign in to comment.