NAME
XML::Chain - a chained way of manipulating and inspecting XML documents
SYNOPSIS
use XML::Chain qw(xc);
# basics
my $div = xc('div', class => 'pretty')
->c('h1')->t('hello')
->up
->c('p', class => 'intro')->t('world')
->root
->a( xc('p')->t('of chained XML.') );
say $div->as_string;
#
hello
world
of chained XML.
my $sitemap =
xc('urlset', xmlns => 'http://www.sitemaps.org/schemas/sitemap/0.9')
->t("\n")
->c('url')
->a('loc', '-' => 'https://metacpan.org/pod/XML::Chain::Selector')
->a('lastmod', '-' => DateTime->from_epoch(epoch => 1507451828)->strftime('%Y-%m-%d'))
->a('changefreq', '-' => 'monthly')
->a('priority', '-' => '0.6')
->up->t("\n")
->c('url')
->a('loc', '-' => 'https://metacpan.org/pod/XML::Chain::Element')
->a('lastmod', '-' => DateTime->from_epoch(epoch => 1507279028)->strftime('%Y-%m-%d'))
->a('changefreq', '-' => 'monthly')
->a('priority', '-' => '0.5')
->up->t("\n");
say $sitemap->as_string;
#
# https://metacpan.org/pod/XML::Chain::Selector2017-10-08monthly0.6
# https://metacpan.org/pod/XML::Chain::Element2017-10-06monthly0.5
#
DESCRIPTION
This module provides a fast and easy way to create and manipulate XML
elements via a set of chained method calls.
EXPORTS
xc
Exported factory method that creates a new XML::Chain::Element object
with the document element provided in the parameters. For example:
my $icon = xc('i', class => 'icon-download icon-white');
#
See also XML::Chain::Selector, from which XML::Chain::Element inherits
all methods, for the element parameter description, and "CHAINED
METHODS" in XML::Chain::Selector for methods on the returned object.
In practice, xc() accepts four input categories: a scalar element name,
an XML::LibXML document or node, an existing selector/element, or some
other reference that IO::Any can read and XML::LibXML can parse.
xc($el_name, @attrs) scalar with 1+ arguments
An element with $el_name will be created as the document element, and
@attrs will be added to it in the same order.
If a hash reference is passed as an argument, its keys and values will
be set as attributes in alphabetical key order.
The attribute name "-" is a special case, and the value will be used
for text content inside the element.
xc($xml_libxml_ref)
Accepted XML::LibXML object types are:
* XML::LibXML::Document
The document is used directly.
* XML::LibXML::Node
The node is used as the document element.
If you need custom parser behavior, parse the XML yourself with your
own XML::LibXML instance and pass the resulting document or node to
xc().
xc($what_ref)
Any other reference will be passed to "slurp($what)" in IO::Any, then
parsed by XML::Chain's private safe default parser, and the result will
be set as the document element.
The default parser disables network access, external DTD loading,
automatic entity expansion, and recovery from malformed XML. If you
need different parser behavior, parse the XML yourself and pass the
resulting XML::LibXML::Document or XML::LibXML::Node to xc().
say xc([$tmp_dir, 't01.xml'])->as_string
say xc(\'and
head
')
->find('//h1')->count
xc($scalar)
An element with $scalar will be created as the document element.
say xc('body');
CHAINED METHODS, METHODS and ELEMENT METHODS
See XML::Chain::Selector and XML::Chain::Element.
METHODS
new
Creates a new XML::Chain object. Optional named arguments is dom (an
existing XML::LibXML::Document).
dom
Gets or sets the current XML::LibXML::Document instance used by the
object.
CHAINED DOCUMENT METHODS
xc('body')->t('save me')->set_io_any([$tmp_dir, 't01.xml'])->store;
# $tmp_dir/t01.xml file now consists of:
save me
xc([$tmp_dir, 't01.xml'])->empty->c('div')->t('updated')->store;
# $tmp_dir/t01.xml file now consists of:
updated
set_io_any
Stores $what, $options for IO::Any for future use with ->store().
store
Calls IO::Any->spew($io_any, $self->as_string, {atomic => 1}) to save
XML back to the target configured via set_io_any.
document_element
Returns the document root element as an XML::Chain::Element object.
This is a convenience method equivalent to ->root on a selector.
my $root = $xc->document_element;
CONTRIBUTORS & CREDITS
Initially inspired by Strophe.Builder, then also by jQuery.
The following people have contributed to XML::Chain by committing their
code, sending patches, reporting bugs, asking questions, suggesting
useful advice, nitpicking, chatting on IRC or commenting on my blog (in
no particular order):
Slaven Rezic
Vienna.pm (for listening to my talk and providing valuable feedback)
Mohammad S Anwar
AI
you?
Also thanks to https://geizhals.at/, https://www.riedellskates.eu/ and
https://apa.at/.
BUGS
Please report any bugs or feature requests via
https://github.com/meon/XML-Chain/issues.
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.
----------------------------------------------------------------------------
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:
Johnny Thinker
jt
Hey
1
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')
#
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');
# one
two
t, append_text
Appends text to the current elements.
xc('span')->t('some')->t(' ')->t('more text')
# some more text
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;
# this is important!
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->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');
# 1
2
3
4
','rename using each()');
Loops through all selected elements and calls the callback for each
one.
map_selection
my $children = xc(\'')->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
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(\'
')->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;
#
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
# 1
2
3
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:
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.
----------------------------------------------------------------------------
NAME
XML::Chain::Element - helper class for XML::Chain representing a single
element
SYNOPSIS
xc('body')->c('h1')->t('title')->root
DESCRIPTION
Returned by "single" in XML::Chain::Selector.
METHODS
new
Creates a new element wrapper.
name
Returns the element name.
as_xml_libxml
Returns an XML::LibXML::Element object.
current_elements
Returns the element wrapped in an array reference for internal
consistency with XML::Chain::Selector. Selectors always work with
arrays of elements, and Element overrides this to return its single
element as a 1-element array.
XML::Chain::Selector methods
All XML::Chain::Selector methods work here as well.
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.