NAME
XML::Chain::Selector - selector for traversing XML::Chain
SYNOPSIS
my $user = xc('user', xmlns => 'http://testns')->auto_indent({chars=>' 'x4})
->a('name', '-' => 'Johnny Thinker')
->a('username', '-' => 'jt')
->c('bio')
->c('div', xmlns => 'http://www.w3.org/1999/xhtml')
->a('h1', '-' => 'about')
->a('p', '-' => '...')
->up
->a('greeting', '-' => 'Hey')
->up
->a('active', '-' => '1')
->root;
say $user->as_string;
Will print:
<user xmlns="http://testns">
<name>Johnny Thinker</name>
<username>jt</username>
<bio>
<div xmlns="http://www.w3.org/1999/xhtml">
<h1>about</h1>
<p>...</p>
</div>
<greeting>Hey</greeting>
</bio>
<active>1</active>
</user>
DESCRIPTION
XML::Chain::Selector represents the current selection of one or more XML nodes inside an XML::Chain document. Most chained methods either modify those nodes or return a new selector with an updated selection.
When exactly one node is selected, XML::Chain may return an XML::Chain::Element object instead, which is a subclass for the single-element case.
CHAINED METHODS
c, append_and_select
Appends a new element to the current elements and changes the context to them. The new element is defined by the parameters:
$xc->c('i', class => 'icon-download icon-white')
# <i class="icon-download icon-white"/>
The first parameter is the element name, followed by optional element attributes.
a, append
Appends a new element to the current elements and then moves the current selection back to the parent elements.
xc('body')
->a('p', '-' => 'one')
->a('p', '-' => 'two');
# <body><p>one</p><p>two</p></body>
t, append_text
Appends text to the current elements.
xc('span')->t('some')->t(' ')->t('more text')
# <span>some more text</span>
The first parameter is the text to append.
root
Sets the document element as the current element.
say xc('p')
->t('this ')
->a(xc('b')->t('is'))
->t(' important!')
->root->as_string;
# <p>this <b>is</b> important!</p>
up, parent
Traverses the current elements and replaces them with their parents. When called on the document root element, returns the same element unchanged (idempotent). This enables safe multichaining like ->parent->parent without needing to check whether you've reached the root.
my $root = xc('<root><child></child></root>');
$root->parent->name eq 'root';
find
say $xc->find('//p/b[@class="less"]')->text_content;
say $xc->find('//xhtml:div', xhtml => 'http://www.w3.org/1999/xhtml')->count;
Looks up elements by XPath and sets them as the current elements. Optional namespace prefixes for lookups can be specified. Any globally registered namespace prefixes from "reg_global_ns" can be used.
children
Sets all child elements of the current elements as the current elements. Non-element child nodes, such as text nodes and comments, are skipped.
first
Sets the first current element as the current element.
empty
Removes all child nodes from the current elements.
rename
my $body = xc('bodyz')->rename('body');
# <body/>
Renames node name(s).
attr
my $img = xc('img')->attr('href' => '#', 'title' => 'image-title');
# <img href="#" title="image-title"/>
say $img->attr('title')
# image-title
say $img->attr('title' => undef)
# <img href="#"/>
Gets or sets element attributes. With one argument, it returns the attribute value; otherwise, it sets the attributes. Setting an attribute to undef removes it from the element.
each
# rename using each
$body->rename('body');
$body
->a(xc('p.1')->t(1))
->a(xc('p.2')->t(2))
->a(xc('div')->t(3))
->a(xc('p.3')->t(4))
->each(sub { $_->rename('p') if $_->name =~ m/^p[.]/ });
is($body, '<body><p>1</p><p>2</p><div>3</div><p>4</p></body>','rename using each()');
Loops through all selected elements and calls the callback for each one.
map_selection
my $children = xc(\'<root><a/><b/><c/></root>')->children->map_selection(sub { $_ });
# returns a selector with the same elements
my $first_children = $root->find('//p')->map_selection(sub { $_->children->first });
# returns a selector of the first child of each <p>
Applies the callback to each selected element ($_ is set to the element). Returns a new selector built from all XML::Chain::Selector objects returned by the callback. Elements for which the callback returns nothing (or a non-selector value) are omitted from the result. The DOM is never modified.
grep_selection
my $ps = xc(\'<body><p/><div/><p/></body>')->children->grep_selection(sub { $_->name eq 'p' });
# $ps->count == 2
Filters the selection. Returns a new selector containing only the elements for which the callback returns a true value ($_ is set to the element). Implemented in terms of "map_selection".
remap
xc('body')->a('p', i => 1)->children->remap(
sub {
(map {xc('e', i => $_)} 1 .. 3), $_;
}
)->root;
# <body><e i="1"/><e i="2"/><e i="3"/><p i="1"/></body>
Replaces all selected elements with the elements returned by the callback.
rm, remove_and_parent
my $pdiv = xc('base')
->a(xc('p')->t(1))
->a(xc('p')->t(2))
->a(xc('div')->t(3))
->a(xc('p')->t(4));
my $p = $pdiv->find('//p');
# $pdiv->find('//p[position()=3]')->rm->name eq 'base'
# $p->count == 2 # deleted elements are skipped also in old selectors
# <base><p>1</p><p>2</p><div>3</div></base>
Deletes current elements and returns their parent.
auto_indent
(experimental feature; useful for debugging, but it needs more testing; works only on the element for which as_string is called at that moment)
my $simple = xc('div')
->auto_indent(1)
->a('div', '-' => 'in1')
->a('div', '-' => 'in2')
->t('in2.1')
->a('div', '-' => 'in3')
;
say $simple->as_string;
Will print:
<div>
<div>in1</div>
<div>in2</div>
in2.1
<div>in3</div>
</div>
Turns tidy/auto-indentation of document elements on or off. The default indentation characters are tabs.
The argument can be either a true/false scalar or a hashref with indentation options. Currently, {chars=' 'x4}> sets the indentation characters to four spaces.
CHAINED DOCUMENT METHODS
See "CHAINED DOCUMENT METHODS" in XML::Chain.
METHODS
new
Creates a new selector object from named arguments.
current_elements
Gets or sets the internal array reference of currently selected elements.
as_string, toString
Returns a string representation of the current XML elements. Call root first to get a string representing the whole document.
$xc->as_string
$xc->root->as_string
as_xml_libxml
Returns the current elements as XML::LibXML objects. In list context, selectors may return multiple nodes. For the single-element case, "as_xml_libxml" in XML::Chain::Element returns one XML::LibXML::Element object.
text_content
Returns the text content of all current XML elements.
count / size
say $xc->find('//b')->count;
Returns the number of current elements.
single
my $lxml_el = $xc->find('//b')->first->as_xml_libxml;
Checks that there is exactly one current element and returns it as an XML::Chain::Element object. It throws an exception if the selection is empty or contains more than one element.
reg_global_ns
Registers a namespace prefix on the document element so that it can be used later in "find" calls. The optional third argument controls whether the namespace is activated on the root element.
$sitemap->reg_global_ns('i' => 'http://www.google.com/schemas/sitemap-image/1.1');
$sitemap->reg_global_ns('s' => 'http://www.sitemaps.org/schemas/sitemap/0.9');
say $sitemap->find('/s:urlset/s:url/i:image')->count
# 2
document_element
Returns the document root element as an XML::Chain::Element object. This is an alias for root.
set_io_any
Stores $what, $options for IO::Any for future use with store. See "set_io_any" in XML::Chain for details.
store
Saves the XML to the target configured via set_io_any. See "store" in XML::Chain for details.
data
Stores and retrieves arbitrary metadata on selected elements without affecting the XML content (jQuery-style .data() method).
# Set data on element
$element->data(user_id => 42);
$element->data(status => 'active');
# Get specific data key
my $user_id = $element->data('user_id');
# Get all data keys as hash
my $all = $element->data;
# Set on multiple elements
$elements->data(processed => 1);
Calling with no arguments returns a hash reference of all stored data for the first element in the selection.
Calling with one argument returns the value for that key in the first element.
Calling with two or more arguments sets the key/value on all elements in the selection and returns $self for chaining.
Important: Data storage is tied to element identity within a document. If an element is copied or imported to another document, the data does not survive the operation (the new element will have an empty data store).
AUTHOR
Jozef Kutej
COPYRIGHT & LICENSE
Copyright 2017 Jozef Kutej, all rights reserved.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.