Name
Data::Edit::Xml - Edit data held in xml format
Synopsis
Create a new xml parse tree:
my $a = Data::Edit::Xml::new("<a><b><c/></b><d><c/></d></a>");
Print the parse tree:
say STDERR -p $a;
to get:
<a>
<b>
<c/>
</b>
<d>
<c/>
</d>
</a>
Cut out c under b but not under d in the created tree by traversing in post-order applying a sub to each node to cut out c when we are at c under b under a.
In object oriented style:
$a->by(sub {$_->cut if $_->at(qw(c b a))});
In chained exit style:
$a->byX(sub {$_->at(qw(c b a))->cut});
In operator style:
$a x= sub {--$_ if $_ <= [qw(c b a)]};
Print the transformed parse tree
say STDERR -p $a;
to get:
<a>
<b/>
<d>
<c/>
</d>
</a>
DocBook to Dita
To transform some DocBook xml into Dita:
use Data::Edit::Xml;
# Parse the DocBook xml
my $a = Data::Edit::Xml::new(<<END);
<sli>
<li>
<p>Diagnose the problem</p>
<p>This can be quite difficult</p>
<p>Sometimes impossible</p>
</li>
<li>
<p><pre>ls -la</pre></p>
<p><pre>
drwxr-xr-x 2 phil phil 4096 Jun 15 2016 Desktop
drwxr-xr-x 2 phil phil 4096 Nov 9 20:26 Downloads
</pre></p>
</li>
</sli>
END
# Transform to Dita step 1
$a->by(sub
{my ($o, $p) = @_;
if ($o->at(qw(pre p li sli)) and $o->isOnlyChild)
{$o->change($p->isFirst ? qw(cmd) : qw(stepresult));
$p->unwrap;
}
elsif ($o->at(qw(li sli)) and $o->over(qr(\Ap( p)+\Z)))
{$_->change($_->isFirst ? qw(cmd) : qw(info)) for $o->contents;
}
});
# Transform to Dita step 2
$a->by(sub
{my ($o) = @_;
$o->change(qw(step)) if $o->at(qw(li sli));
$o->change(qw(steps)) if $o->at(qw(sli));
$o->id = 's'.($o->position+1) if $o->at(qw(step));
$o->id = 'i'.($o->index+1) if $o->at(qw(info));
$o->wrapWith(qw(screen)) if $o->at(qw(CDATA stepresult));
});
# Print the results
say STDERR -p $a;
Produces:
<steps>
<step id="s1">
<cmd>Diagnose the problem
</cmd>
<info id="i1">This can be quite difficult
</info>
<info id="i2">Sometimes impossible
</info>
</step>
<step id="s2">
<cmd>ls -la
</cmd>
<stepresult>
<screen>
drwxr-xr-x 2 phil phil 4096 Jun 15 2016 Desktop
drwxr-xr-x 2 phil phil 4096 Nov 9 20:26 Downloads
</screen>
</stepresult>
</step>
</steps>
Description
Immediately useful methods
These methods are the ones most likely to be of immediate useful to anyone using this package for the first time:
Confirm that the node has the specified ancestry and return the starting node if it does else undef.
Return the value of an attribute of the current node as an lvalue sub.
Post-order traversal of a parse tree or sub tree calling the specified sub at each node and returning the specified starting node. The sub is passed references to the current node and all of its ancestors. The value of the current node is also made available via $_.
Change the name of a node, optionally confirming that the node is in a specified context and return the node.
Cut out a node so that it can be reinserted else where in the parse tree.
Return the node reached from the specified node via the specified path: (index position?)* where index is the tag of the next node to be chosen and position is the optional zero based position within the index of those tags under the current node. Position defaults to zero if not specified. Position can also be negative to index back from the top of the index array. * can be used as the last position to retrieve all nodes with the final tag.
New parse - call this method statically as in Data::Edit::Xml::new(file or string) or with no parameters and then use "input", "inputFile", "inputString", "errorFile" to provide specific parameters for the parse, then call "parse" to perform the parse and return the parse tree.
Return a readable string representing a node of a parse tree and all the nodes below it. Or use -p $node
Return the node previous to the specified node.
Place a cut out or new node last in the content of the specified node and return the new node.
Unwrap a node by inserting its content into its parent at the point containing the node; returns the parent node.
Wrap the original node in a new node forcing the original node down deepening the parse tree; return the new wrapping node.
Construction
Create a parse tree, either by parsing a file or string, or, node by node
File or String
Construct a parse tree from a file or a string
new($)
New parse - call this method statically as in Data::Edit::Xml::new(file or string) or with no parameters and then use "input", "inputFile", "inputString", "errorFile" to provide specific parameters for the parse, then call "parse" to perform the parse and return the parse tree.
1 $fileNameOrString File name or string
Example:
my $x = Data::Edit::Xml::new(<<END);
<a><b><c/></b><d><e/></d></a>
END
ok -p $x eq <<END;
<a>
<b>
<c/>
</b>
<d>
<e/>
</d>
</a>
END
This is a static method and so should be invoked as:
Data::Edit::Xml::new
content :lvalue
Content of command: the nodes immediately below this node in the order in which they appeared in the source text, see also "Contents".
numbers :lvalue
Nodes by number.
attributes :lvalue
The attributes of this node, see also: "Attributes". The frequently used attributes: class, id, href, outputclass can be accessed by an lvalue method as in: $node->id = 'c1'.
conditions :lvalue
Conditional strings attached to a node, see "Conditions".
indexes :lvalue
Indexes to sub commands by tag in the order in which they appeared in the source text.
labels :lvalue
The labels attached to a node to provide addressability from other nodes, see: "Labels".
errorsFile :lvalue
Error listing file. Use this parameter to explicitly set the name of the file that will be used to write an parse errors to. By default this file is named: zzzParseErrors/out.data.
inputFile :lvalue
Source file of the parse if this is the parser root node. Use this parameter to explicitly set the file to be parsed.
input :lvalue
Source of the parse if this is the parser root node. Use this parameter to specify some input either as a string or as a file name for the parser to convert into a parse tree.
inputString :lvalue
Source string of the parse if this is the parser root node. Use this parameter to explicitly set the string to be parsed.
number :lvalue
Number of this node, see findByNumber and numberTree.
parent :lvalue
Parent node of this node or undef if the oarser root node. See also "Traversal" and "Navigation". Consider as read only.
parser :lvalue
Parser details: the root node of a tree is the parse node for that tree. Consider as read only.
tag :lvalue
Tag name for this node, see also "Traversal" and "Navigation". Consider as read only.
text :lvalue
Text of this node but only if it is a text node, i.e. the tag is cdata() <=> "isText" is true.
cdata()
The name of the tag to be used to represent text - this tag must not also be used as a command tag otherwise the parser will confess.
parse($)
Parse input xml specified via: inputFile, input or inputString.
1 $parser Parser created by L</new>
Example:
my $x = Data::Edit::Xml::new;
$x->inputString = <<END;
<a id="aa"><b id="bb"><c id="cc"/></b></a>
END
$x->parse;
Node by Node
Construct a parse tree node by node.
newText($$)
Create a new text node.
1 undef Any reference to this package
2 $text Content of new text node
Example:
ok -p $x eq <<END;
<a class="aa" id="1">
<b class="bb" id="2"/>
</a>
END
$x->putLast($x->newText("t"));
ok -p $x eq <<END;
<a class="aa" id="1">
<b class="bb" id="2"/>
t
</a>
END
newTag($$%)
Create a new non text node.
1 undef Any reference to this package
2 $command The tag for the node
3 %attributes Attributes as a hash.
Example:
my $x = Data::Edit::Xml::newTree("a", id=>1, class=>"aa");
$x->putLast($x->newTag("b", id=>2, class=>"bb"));
ok -p $x eq <<END;
<a class="aa" id="1">
<b class="bb" id="2"/>
</a>
END
newTree($%)
Create a new tree.
1 $command The name of the root node in the tree
2 %attributes Attributes of the root node in the tree as a hash.
Example:
my $x = Data::Edit::Xml::newTree("a", id=>1, class=>"aa");
ok -s $x eq '<a class="aa" id="1"/>';
replaceSpecialChars($)
Replace < > " with < > " Larry Wall's excellent Xml parser unfortunately replaces < > " & etc. with their expansions in text by default and does not seem to provide an obvious way to stop this behavior, so we have to put them back gain using this method. Worse, we cannot decide whether to replace & with & or leave it as is: consequently you might have to examine the instances of & in your output text and guess based on the context.
1 $string String to be edited.
renew($)
Returns a renewed copy of the parse tree: use this method if you have added nodes via the "Put as text" methods and wish to reprocess them.
1 $node Parse tree.
Example:
ok -s $a eq '<a id="1"><b id="4"/><b id="6"/><b id="2"><d id="7"/><c id="3"/></b><b id="5"/></a>';
my $x = $a->renew;
ok -s $x eq '<a id="1"><b id="4"/><b id="6"/><b id="2"><d id="7"/><c id="3"/></b><b id="5"/></a>';
clone($)
Return a clone of the parse tree: use this method if you want to make changes to an exact copy of the parse tree.
1 $node Parse tree.
Example:
my $s = '<a><b><c id="1"/><c id="2"/><d/><c id="3"/><c id="4"/></b></a>';
ok -s $A eq $s;
my $a = $A->clone;
ok -s $a eq $s;
equals($$)
Return the first node if the two parse trees are equal, else undef if they are not equal.
1 $node1 Parse tree 1
2 $node2 Parse tree 2.
Example:
my $s = '<a><b><c id="1"/><c id="2"/><d/><c id="3"/><c id="4"/></b></a>';
ok -s $A eq $s;
my $a = $A->clone;
ok $a->equals($A);
Use equalsX to execute equals but die 'equals' instead of returning undef
save($$)
Save a copy of the parse tree to a file which can be restored and return the saved node.
1 $node Parse tree
2 $file File.
restore($)
Return a parse tree from a copy saved in a file by "save".
1 $file File
Use restoreX to execute restore but die 'restore' instead of returning undef
This is a static method and so should be invoked as:
Data::Edit::Xml::restore
Stringification
Create a string representation of the parse tree with optional selection of nodes via conditions.
Print the parse tree. Normally use prettyString string to format the xml in a readable yet reparseable manner; use string string to format the xml densely in a reparseable manner; use the other methods to produce unreparseable strings conveniently formatted to assist various specialized operations such as debugging CDATA, using labels or creating tests. A number of the file test operators can also be conveniently used to print parse trees in these formats.
string($)
Return a dense string representing a node of a parse tree and all the nodes below it. Or use -s $node
1 $node Start node.
Example:
my $x = Data::Edit::Xml::new(<<END);
<a><b><c/></b><d><e/></d></a>
END
ok -p $x eq <<END;
<a>
<b>
<c/>
</b>
<d>
<e/>
</d>
</a>
END
stringQuoted($)
Return a quoted string representing a parse tree a node of a parse tree and all the nodes below it. Or use -o $node
1 $node Start node
stringReplacingIdWithLabels($)
Return a string representing the specified parse tree with the id attribute of each node set to the Labels attached to each node.
1 $node Start node.
stringReplacingIdWithLabelsQuoted($)
Return a quoted string representing a node of a parse tree and all the nodes below it with all the id attributes replaced with the labels attached to each node.
1 $node Start node.
contentString($)
Return a string representing all the nodes below a node of a parse tree.
1 $node Start node.
prettyString($$)
Return a readable string representing a node of a parse tree and all the nodes below it. Or use -p $node
1 $node Start node
2 $depth Optional depth.
Example:
my $s = <<END;
<a>
<b>
<A/>
<B/>
</b>
<c>
<C/>
<D/>
</c>
</a>
END
my $a = Data::Edit::Xml::new($s);
ok $s eq $a->prettyString;
ok $s eq -p $a;
prettyStringNumbered($$)
Return a readable string representing a node of a parse tree and all the nodes below it with a number attached to each tag. The node numbers can then be used as described in Order to monitor changes to the parse tree.
1 $node Start node
2 $depth Optional depth.
prettyStringShowingCDATA($$)
Return a readable string representing a node of a parse tree and all the nodes below it with the text fields wrapped with <CDATA>...</CDATA>.
1 $node Start node
2 $depth Optional depth.
Example:
my $a = Data::Edit::Xml::new("<a>1<A/>2<B/>3<C/>4<D/>5<E/>6<F/>7<G/>8<H/>9</a>");
map {$_->replaceWithBlank} grep {$_->isText} $a->contents;
map {$_->cut} grep {$_->tag =~ m/\A[BDFH]\Z/} $a->contents;
ok $a->prettyStringShowingCDATA eq <<'END';
<a><CDATA> </CDATA>
<A/>
<CDATA> </CDATA>
<C/>
<CDATA> </CDATA>
<E/>
<CDATA> </CDATA>
<G/>
<CDATA> </CDATA>
</a>
END
prettyStringEnd($)
Return a readable string representing a node of a parse tree and all the nodes below it as a here document
1 $node Start node
PrettyContentString($)
Return a readable string representing all the nodes below a node of a parse tree - infrequent use and so capitalized to avoid being presented as an option by Geany.
1 $node Start node.
Conditions
Print a subset of the the parse tree determined by the conditions attached to it.
stringWithConditions($@)
Return a string representing a node of a parse tree and all the nodes below it subject to conditions to select or reject some nodes.
1 $node Start node
2 @conditions Conditions to be regarded as in effect.
addConditions($@)
Add conditions to a node and return the node.
1 $node Node
2 @conditions Conditions to add.
deleteConditions($@)
Delete conditions applied to a node and return the node.
1 $node Node
2 @conditions Conditions to add.
listConditions($)
Return a list of conditions applied to a node.
1 $node Node.
Attributes
Get or set the attributes of nodes in the parse tree. Well known attributes can be set directly via lvalue subs for less well known attributes use attr.
class :lvalue
Attribute class for a node as an lvalue sub.
href :lvalue
Attribute href for a node as an lvalue sub.
id :lvalue
Attribute id for a node as an lvalue sub.
outputclass :lvalue
Attribute outputclass for a node as an lvalue sub.
attr :lvalue($$)
Return the value of an attribute of the current node as an lvalue sub.
1 $node Node in parse tree
2 $attribute Attribute name.
attrs($@)
Return the values of the specified attributes of the current node.
1 $node Node in parse tree
2 @attributes Attribute names.
attrCount($)
Return the number of attributes in the specified node.
1 $node Node in parse tree
Example:
my $x = Data::Edit::Xml::newTree("a", id=>1, class=>"aa");
ok $x->attrCount == 2;
getAttrs($)
Return a sorted list of all the attributes on this node.
1 $node Node in parse tree.
setAttr($@)
Set the value of an attribute in a node and return the node.
1 $node Node in parse tree
2 %values (attribute name=>new value)*
deleteAttr($$$)
Delete the attribute, optionally checking its value first and return the node.
1 $node Node
2 $attr Attribute name
3 $value Optional attribute value to check first.
deleteAttrs($@)
Delete any attributes mentioned in a list without checking their values and return the node.
1 $node Node
2 @attrs Attribute name
renameAttr($$$)
Change the name of an attribute regardless of whether the new attribute already exists and return the node.
1 $node Node
2 $old Existing attribute name
3 $new New attribute name.
changeAttr($$$)
Change the name of an attribute unless it has already been set and return the node.
1 $node Node
2 $old Existing attribute name
3 $new New attribute name.
renameAttrValue($$$$$)
Change the name and value of an attribute regardless of whether the new attribute already exists and return the node.
1 $node Node
2 $old Existing attribute name
3 $oldValue Existing attribute value
4 $new New attribute name
5 $newValue New attribute value.
changeAttrValue($$$$$)
Change the name and value of an attribute unless it has already been set and return the node.
1 $node Node
2 $old Existing attribute name
3 $oldValue Existing attribute value
4 $new New attribute name
5 $newValue New attribute value.
Traversal
Traverse the parse tree in various orders applying a sub to each node.
by($$@)
Post-order traversal of a parse tree or sub tree calling the specified sub at each node and returning the specified starting node. The sub is passed references to the current node and all of its ancestors. The value of the current node is also made available via $_.
1 $node Starting node
2 $sub Sub to call for each sub node
3 @context Accumulated context.
Example:
my $x = Data::Edit::Xml::new(<<END);
<a><b><c/></b><d><e/></d></a>
END
my $s; $x->by(sub{$s .= $_->tag}); ok $s eq "cbeda"
byX($$@)
Post-order traversal of a parse tree or sub tree calling the specified sub within eval{} at each node and returning the specified starting node. The sub is passed references to the current node and all of its ancestors. The value of the current node is also made available via $_.
1 $node Starting node
2 $sub Sub to call
3 @context Accumulated context.
Example:
my $x = Data::Edit::Xml::new(<<END);
<a><b><c/></b><d><e/></d></a>
END
my $s; $x->by(sub{$s .= $_->tag}); ok $s eq "cbeda"
byReverse($$@)
Reverse post-order traversal of a parse tree or sub tree calling the specified sub at each node and returning the specified starting node. The sub is passed references to the current node and all of its ancestors. The value of the current node is also made available via $_.
1 $node Starting node
2 $sub Sub to call for each sub node
3 @context Accumulated context.
Example:
my $x = Data::Edit::Xml::new(<<END);
<a><b><c/></b><d><e/></d></a>
END
my $s; $x->byReverse(sub{$s .= $_->tag}); ok $s eq "edcba"
byReverseX($$@)
Reverse post-order traversal of a parse tree or sub tree calling the specified sub within eval{} at each node and returning the specified starting node. The sub is passed references to the current node and all of its ancestors. The value of the current node is also made available via $_.
1 $node Starting node
2 $sub Sub to call for each sub node
3 @context Accumulated context.
Example:
my $x = Data::Edit::Xml::new(<<END);
<a><b><c/></b><d><e/></d></a>
END
my $s; $x->byReverse(sub{$s .= $_->tag}); ok $s eq "edcba"
down($$@)
Pre-order traversal down through a parse tree or sub tree calling the specified sub at each node and returning the specified starting node. The sub is passed references to the current node and all of its ancestors. The value of the current node is also made available via $_.
1 $node Starting node
2 $sub Sub to call for each sub node
3 @context Accumulated context.
Example:
my $s; $x->down(sub{$s .= $_->tag}); ok $s eq "abcde"
downX($$@)
Pre-order traversal down through a parse tree or sub tree calling the specified sub within eval{} at each node and returning the specified starting node. The sub is passed references to the current node and all of its ancestors. The value of the current node is also made available via $_.
1 $node Starting node
2 $sub Sub to call for each sub node
3 @context Accumulated context.
Example:
my $s; $x->down(sub{$s .= $_->tag}); ok $s eq "abcde"
downReverse($$@)
Reverse pre-order traversal down through a parse tree or sub tree calling the specified sub at each node and returning the specified starting node. The sub is passed references to the current node and all of its ancestors. The value of the current node is also made available via $_.
1 $node Starting node
2 $sub Sub to call for each sub node
3 @context Accumulated context.
Example:
my $x = Data::Edit::Xml::new(<<END);
<a><b><c/></b><d><e/></d></a>
END
my $s; $x->downReverse(sub{$s .= $_->tag}); ok $s eq "adebc"
downReverseX($$@)
Reverse pre-order traversal down through a parse tree or sub tree calling the specified sub within eval{} at each node and returning the specified starting node. The sub is passed references to the current node and all of its ancestors. The value of the current node is also made available via $_.
1 $node Starting node
2 $sub Sub to call for each sub node
3 @context Accumulated context.
Example:
my $x = Data::Edit::Xml::new(<<END);
<a><b><c/></b><d><e/></d></a>
END
my $s; $x->downReverse(sub{$s .= $_->tag}); ok $s eq "adebc"
through($$$@)
Traverse parse tree visiting each node twice calling the specified sub at each node and returning the specified starting node. The subs are passed references to the current node and all of its ancestors. The value of the current node is also made available via $_.
1 $node Starting node
2 $before Sub to call when we meet a node
3 $after Sub to call we leave a node
4 @context Accumulated context.
Example:
my $s; my $n = sub{$s .= $_->tag}; $x->through($n, $n);
ok $s eq "abccbdeeda"
throughX($$$@)
Traverse parse tree visiting each node twice calling the specified sub within eval{} at each node and returning the specified starting node. The sub is passed references to the current node and all of its ancestors. The value of the current node is also made available via $_.
1 $node Starting node
2 $before Sub to call when we meet a node
3 $after Sub to call we leave a node
4 @context Accumulated context.
Example:
my $s; my $n = sub{$s .= $_->tag}; $x->through($n, $n);
ok $s eq "abccbdeeda"
Contents
The immediate content of each node, i.e. the children of a node.
contents($)
Return all the nodes contained by this node either as an array or as a reference to such an array.
1 $node Node.
contentBeyond($)
Return all the sibling nodes following this node at the level of this node.
1 $node Node.
contentBefore($)
Return all the sibling nodes preceding this node at the level of this node.
1 $node Node.
contentAsTags($)
Return a string containing the tags of all the nodes contained by this node separated by single spaces.
1 $node Node.
contentBeyondAsTags($)
Return a string containing the tags of all the sibling nodes following this node separated by single spaces.
1 $node Node.
contentBeforeAsTags($)
# Return a string containing the tags of all the sibling nodes preceding this node separated by single spaces.
1 $node Node.
position($)
Return the index of a node in its parent's content.
1 $node Node.
index($)
Return the index of a node in its parent index.
1 $node Node.
present($@)
Return the count of the number of the specified tag types present immediately under a node.
1 $node Node
2 @names Possible tags immediately under the node.
isText($)
Confirm that this is a text node.
1 $node Node to test.
Use isTextX to execute isText but die 'isText' instead of returning undef
isBlankText($)
Confirm that this is a text node and that it is blank.
1 $node Node to test.
Use isBlankTextX to execute isBlankText but die 'isBlankText' instead of returning undef
Navigation
Move around in the parse tree
get($@)
Return the node reached from the specified node via the specified path: (index position?)* where index is the tag of the next node to be chosen and position is the optional zero based position within the index of those tags under the current node. Position defaults to zero if not specified. Position can also be negative to index back from the top of the index array. * can be used as the last position to retrieve all nodes with the final tag.
1 $node Node
2 @position Search specification.
Example:
ok Data::Edit::Xml::new(<<END)->go(qw(b c -1 e))->at(qw(e c b a));
<a>
<b>
<c> <d/> </c>
<c> <e/> </c>
</b>
</a>
END
Use getX to execute get but die 'get' instead of returning undef
c($$)
Return an array of all the nodes with the specified tag below the specified node.
1 $node Node
2 $tag Tag.
first($)
Return the first node below this node.
1 $node Node.
Use firstNonBlank to skip a (rare) initial blank text CDATA. Use firstNonBlankX to die rather then receive a returned undef or false result.
Use firstX to execute first but die 'first' instead of returning undef
firstBy($@)
Return a list of the first instance of each specified tag encountered in a post-order traversal from the specified node or a hash of all first instances if no tags are specified.
1 $node Node
2 @tags Tags to search for.
firstDown($@)
Return a list of the first instance of each specified tag encountered in a pre-order traversal from the specified node or a hash of all first instances if no tags are specified.
1 $node Node
2 @tags Tags to search for.
lastBy($@)
Return a list of the last instance of each specified tag encountered in a post-order traversal from the specified node or a hash of all first instances if no tags are specified.
1 $node Node
2 @tags Tags to search for.
lastDown($@)
Return a list of the last instance of each specified tag encountered in a pre-order traversal from the specified node or a hash of all first instances if no tags are specified.
1 $node Node
2 @tags Tags to search for.
firstIn($@)
Return the first node matching one of the named tags under the specified node.
1 $node Node
2 @tags Tags to search for.
Example:
ok $a->prettyStringShowingCDATA eq <<'END';
<a><CDATA> </CDATA>
<A/>
<CDATA> </CDATA>
<C/>
<CDATA> </CDATA>
<E/>
<CDATA> </CDATA>
<G/>
<CDATA> </CDATA>
</a>
END
ok $a->firstIn(qw(b B c C))->tag eq qq(C);
Use firstInX to execute firstIn but die 'firstIn' instead of returning undef
firstContextOf($@)
Return the first node encountered in the specified context in a depth first post-order traversal of the parse tree.
1 $node Node
2 @context Array of tags specifying context.
Use firstContextOfX to execute firstContextOf but die 'firstContextOf' instead of returning undef
last($)
Return the last node below this node.
1 $node Node.
Use lastNonBlank to skip a (rare) initial blank text CDATA. Use lastNonBlankX to die rather then receive a returned undef or false result.
Use lastX to execute last but die 'last' instead of returning undef
lastIn($@)
Return the first node matching one of the named tags under the specified node.
1 $node Node
2 @tags Tags to search for.
Example:
ok $a->prettyStringShowingCDATA eq <<'END';
<a><CDATA> </CDATA>
<A/>
<CDATA> </CDATA>
<C/>
<CDATA> </CDATA>
<E/>
<CDATA> </CDATA>
<G/>
<CDATA> </CDATA>
</a>
END
ok $a->lastIn(qw(e E f F))->tag eq qq(E);
Use lastInX to execute lastIn but die 'lastIn' instead of returning undef
lastContextOf($@)
Return the last node encountered in the specified context in a depth first reverse pre-order traversal of the parse tree.
1 $node Node
2 @context Array of tags specifying context.
Use lastContextOfX to execute lastContextOf but die 'lastContextOf' instead of returning undef
next($)
Return the node next to the specified node.
1 $node Node.
Use nextNonBlank to skip a (rare) initial blank text CDATA. Use nextNonBlankX to die rather then receive a returned undef or false result.
Use nextX to execute next but die 'next' instead of returning undef
nextIn($@)
Return the next node matching one of the named tags.
1 $node Node
2 @tags Tags to search for.
Example:
ok $a->prettyStringShowingCDATA eq <<'END';
<a><CDATA> </CDATA>
<A/>
<CDATA> </CDATA>
<C/>
<CDATA> </CDATA>
<E/>
<CDATA> </CDATA>
<G/>
<CDATA> </CDATA>
</a>
END
ok $a->firstIn(qw(b B c C))->nextIn(qw(A G))->tag eq qq(G);
Use nextInX to execute nextIn but die 'nextIn' instead of returning undef
prev($)
Return the node previous to the specified node.
1 $node Node.
Use prevNonBlank to skip a (rare) initial blank text CDATA. Use prevNonBlankX to die rather then receive a returned undef or false result.
Use prevX to execute prev but die 'prev' instead of returning undef
prevIn($@)
Return the next previous node matching one of the named tags.
1 $node Node
2 @tags Tags to search for.
Example:
ok $a->prettyStringShowingCDATA eq <<'END';
<a><CDATA> </CDATA>
<A/>
<CDATA> </CDATA>
<C/>
<CDATA> </CDATA>
<E/>
<CDATA> </CDATA>
<G/>
<CDATA> </CDATA>
</a>
END
ok $a->lastIn(qw(e E f F))->prevIn(qw(A G))->tag eq qq(A);
Use prevInX to execute prevIn but die 'prevIn' instead of returning undef
upto($@)
Return the first ancestral node that matches the specified context.
1 $node Start node
2 @tags Tags identifying context.
Use uptoX to execute upto but die 'upto' instead of returning undef
nextOn($@)
Step forwards as far as possible while remaining on nodes with the specified tags and return the last such node reached or the starting node if no such steps are possible.
1 $node Start node
2 @tags Tags identifying nodes that can be step on to context.
prevOn($@)
Step backwards as far as possible while remaining on nodes with the specified tags and return the last such node reached or the starting node if no such steps are possible.
1 $node Start node
2 @tags Tags identifying nodes that can be step on to context.
Position
Confirm that the position navigated to is the expected position.
at($@)
Confirm that the node has the specified ancestry and return the starting node if it does else undef.
1 $start Starting node
2 @context Ancestry.
Example:
ok Data::Edit::Xml::new(<<END)->go(qw(b c -1 e))->at(qw(e c b a));
<a>
<b>
<c> <d/> </c>
<c> <e/> </c>
</b>
</a>
END
Use atX to execute at but die 'at' instead of returning undef
ancestry($)
Return a list containing: (the specified node, its parent, its parent's parent etc..)
1 $start Starting node.
context($)
Return a string containing the tag of the starting node and the tags of all its ancestors separated by single spaces.
1 $start Starting node.
Example:
ok -p $x eq <<END;
<a>
<b>
<c/>
</b>
<d>
<e/>
</d>
</a>
END
ok $x->go(qw(d e))->context eq 'e d a';
isFirst($)
Confirm that this node is the first node under its parent.
1 $node Node.
Example:
ok -p $x eq <<END;
<a>
<b>
<c/>
</b>
<d>
<e/>
</d>
</a>
END
ok $x->go(qw(b))->isFirst;
Use isFirstX to execute isFirst but die 'isFirst' instead of returning undef
isLast($)
Confirm that this node is the last node under its parent.
1 $node Node.
Example:
ok -p $x eq <<END;
<a>
<b>
<c/>
</b>
<d>
<e/>
</d>
</a>
END
ok $x->go(qw(d))->isLast;
Use isLastX to execute isLast but die 'isLast' instead of returning undef
isOnlyChild($@)
Return the specified node if it is the only node under its parent (and ancestors) ignoring any surrounding blank text.
1 $node Node
2 @tags Optional tags to confirm context.
Example:
my $x = Data::Edit::Xml::new(<<END)->first->first;
<a id="aa"><b id="bb"><c id="cc"/></b></a>
END
ok $x->isOnlyChild;
ok $x->isOnlyChild(qw(c));
ok $x->isOnlyChild(qw(c b));
ok $x->isOnlyChild(qw(c b a));
Use isOnlyChildX to execute isOnlyChild but die 'isOnlyChild' instead of returning undef
isEmpty($)
Confirm that this node is empty, that is: this node has no content, not even a blank string of text.
1 $node Node.
Example:
my $x = Data::Edit::Xml::new(<<END)->first->first;
<a id="aa"><b id="bb"><c id="cc"/></b></a>
END
ok $x->isEmpty;
Use isEmptyX to execute isEmpty but die 'isEmpty' instead of returning undef
over($$)
Confirm that the string representing the tags at the level below this node match a regular expression.
1 $node Node
2 $re Regular expression.
Use overX to execute over but die 'over' instead of returning undef
matchAfter($$)
Confirm that the string representing the tags following this node matches a regular expression.
1 $node Node
2 $re Regular expression.
Use matchAfterX to execute matchAfter but die 'matchAfter' instead of returning undef
matchBefore($$)
Confirm that the string representing the tags preceding this node matches a regular expression
1 $node Node
2 $re Regular expression
Use matchBeforeX to execute matchBefore but die 'matchBefore' instead of returning undef
path($)
Return a list representing the path to a node which can then be reused by get to retrieve the node as long as the structure of the parse tree has not changed along the path.
1 $node Node.
byPosition($)
Return the position of this node in a post-order traversal of the parse tree.
1 $node Node.
byReversePosition($)
Return the position of this node in a reverse post-order traversal of the parse tree.
1 $node Node.
downPosition($)
Return the position of this node in a pre-order traversal of the parse tree.
1 $node Node.
downReversePosition($)
Return the position of this node in a reverse pre-order traversal of the parse tree.
1 $node Node.
Order
Number and verify the order of nodes.
numberNode($)
Ensure that this node has a number.
1 $node Node
findByNumber($$)
Find the node with the specified number as set by numberTree and made visible by prettyStringNumbered in the parse tree containing the specified node and return the found node or undef if no such node exists.
1 $node Node in the parse tree to search
2 $number Number of the node required.
Use findByNumberX to execute findByNumber but die 'findByNumber' instead of returning undef
findByNumbers($@)
Find the nodes with the specified numbers as set by numberTree and made visible by prettyStringNumbered in the parse tree containing the specified node and return the found nodes in a list with undef for nodes that do not exist.
1 $node Node in the parse tree to search
2 @numbers Numbers of the nodes required.
numberTree($)
Ensure that this node and any nodes below it are numbered
1 $node Node.
above($$)
Return the specified node if it is above the specified target otherwise undef
1 $node Node
2 $target Target.
Use aboveX to execute above but die 'above' instead of returning undef
below($$)
Return the specified node if it is below the specified target otherwise undef
1 $node Node
2 $target Target.
Use belowX to execute below but die 'below' instead of returning undef
after($$)
Return the specified node if it occurs after the target node in the parse tree or else undef if the node is above, below or before the target.
1 $node Node
2 $target Targe.t
Use afterX to execute after but die 'after' instead of returning undef
before($$)
Return the specified node if it occurs before the target node in the parse tree or else undef if the node is above, below or after the target.
1 $node Node
2 $target Target.
Use beforeX to execute before but die 'before' instead of returning undef
disordered($@)
Return the first node that is out of the specified order when performing a pre-ordered traversal of the parse tree.
1 $node Node
2 @nodes Following nodes.
ordered($@)
Return the first node if the specified nodes are all in order when performing a pre-ordered traversal of the parse tree else return undef
1 $node Node
2 @nodes Following nodes.
Use orderedX to execute ordered but die 'ordered' instead of returning undef
Editing
Edit the data in the parse tree and change the structure of the parse tree by wrapping and unwrapping nodes, by replacing nodes, by cutting and pasting nodes, by concatenating nodes, by splitting nodes or by adding node as text
change($$@)
Change the name of a node, optionally confirming that the node is in a specified context and return the node.
1 $node Node
2 $name New name
3 @tags Optional: tags defining the required context.
Example:
my $a = Data::Edit::Xml::new('<a/>');
$a->change(qq(b));
ok -s $a eq '<b/>';
Use changeX to execute change but die 'change' instead of returning undef
Wrap and unwrap
Wrap and unwrap nodes to alter the depth of the parse tree
wrapWith($$@)
Wrap the original node in a new node forcing the original node down deepening the parse tree; return the new wrapping node.
1 $old Node
2 $tag Tag for the L<new node|/newTag>
3 %attributes Attributes for the L<new node|/newTag>.
Example:
ok -p $x eq <<END;
<a>
<b>
<c id="11"/>
</b>
</a>
END
$x->go(qw(b c))->wrapWith(qw(C id 1));
ok -p $x eq <<END;
<a>
<b>
<C id="1">
<c id="11"/>
</C>
</b>
</a>
END
wrapUp($@)
Wrap the original node in a sequence of new nodes forcing the original node down deepening the parse tree; return the array of wrapping nodes.
1 $node Node to wrap
2 @tags Tags to wrap the node with - with the uppermost tag rightmost.
Example:
my $c = Data::Edit::Xml::newTree("c", id=>33);
my ($b, $a) = $c->wrapUp(qw(b a));
wrapDown($@)
Wrap the content of the specified node in a sequence of new nodes forcing the original node up deepening the parse tree; return the array of wrapping nodes.
1 $node Node to wrap
2 @tags Tags to wrap the node with - with the uppermost tag rightmost.
Example:
my $a = Data::Edit::Xml::newTree("a", id=>33);
my ($b, $c) = $a->wrapDown(qw(b c));
wrapContentWith($$@)
Wrap the content of a node in a new node, the original content then contains the new node which contains the original node's content; returns the new wrapped node.
1 $old Node
2 $tag Tag for new node
3 %attributes Attributes for new node.
unwrap($)
Unwrap a node by inserting its content into its parent at the point containing the node; returns the parent node.
1 $node Node to unwrap.
Example:
ok -s $x eq "<a>A<b> c </b>B</a>";
$b->unwrap;
ok -s $x eq "<a>A c B</a>";
Replace
Replace nodes in the parse tree with nodes or text
replaceWith($$)
Replace a node (and all its content) with a new node (and all its content) and return the new node.
1 $old Old node
2 $new New node.
replaceWithText($$)
Replace a node (and all its content) with a new text node and return the new node.
1 $old Old node
2 $text Text of new node.
replaceWithBlank($)
Replace a node (and all its content) with a new blank text node and return the new node.
1 $old Old node
Cut and Put
Move nodes around in the parse tree by cutting and pasting them
cut($)
Cut out a node so that it can be reinserted else where in the parse tree.
1 $node Node to cut out.
Example:
ok -p $a eq <<END;
<a id="aa">
<b id="bb">
<c id="cc"/>
</b>
</a>
END
my $c = $a->go(qw(b c))->cut;
ok -p $a eq <<END;
<a id="aa">
<b id="bb"/>
</a>
END
putFirst($$)
Place a cut out or new node at the front of the content of the specified node and return the new node.
1 $old Original node
2 $new New node.
Example:
ok -p $a eq <<END;
<a id="aa">
<b id="bb">
<c id="cc"/>
</b>
</a>
END
my $c = $a->go(qw(b c))->cut;
$a->putFirst($c);
ok -p $a eq <<END;
<a id="aa">
<c id="cc"/>
<b id="bb"/>
</a>
END
putLast($$)
Place a cut out or new node last in the content of the specified node and return the new node.
1 $old Original node
2 $new New node.
Example:
ok -p $a eq <<END;
<a id="aa">
<c id="cc"/>
<b id="bb"/>
</a>
END
$a->putLast($a->go(qw(c))->cut);
ok -p $a eq <<END;
<a id="aa">
<b id="bb"/>
<c id="cc"/>
</a>
END
putNext($$)
Place a cut out or new node just after the specified node and return the new node.
1 $old Original node
2 $new New node.
Example:
ok -p $a eq <<END;
<a id="aa">
<b id="bb"/>
<c id="cc"/>
</a>
END
$a->go(qw(c))->putNext($a->go(qw(b))->cut);
ok -p $a eq <<END;
<a id="aa">
<c id="cc"/>
<b id="bb"/>
</a>
END
putPrev($$)
Place a cut out or new node just before the specified node and return the new node.
1 $old Original node
2 $new New node.
Example:
ok -p $a eq <<END;
<a id="aa">
<c id="cc"/>
<b id="bb"/>
</a>
END
$a->go(qw(c))->putPrev($a->go(qw(b))->cut);
ok -p $a eq <<END;
<a id="aa">
<b id="bb"/>
<c id="cc"/>
</a>
END
Fusion
Join consecutive nodes
concatenate($$)
Concatenate two successive nodes and return the target node.
1 $target Target node to replace
2 $source Node to concatenate.
Example:
my $s = <<END;
<a>
<b>
<A/>
<B/>
</b>
<c>
<C/>
<D/>
</c>
</a>
END
my $a = Data::Edit::Xml::new($s);
$a->go(qw(b))->concatenate($a->go(qw(c)));
my $t = <<END;
<a>
<b>
<A/>
<B/>
<C/>
<D/>
</b>
</a>
END
ok $t eq -p $a;
concatenateSiblings($)
Concatenate preceding and following nodes as long as they have the same tag as the specified node and return the specified node.
1 $node Concatenate around this node.
Example:
ok -p $a eq <<END;
<a>
<b>
<c id="1"/>
</b>
<b>
<c id="2"/>
</b>
<b>
<c id="3"/>
</b>
<b>
<c id="4"/>
</b>
</a>
END
$a->go(qw(b 3))->concatenateSiblings;
ok -p $a eq <<END;
<a>
<b>
<c id="1"/>
<c id="2"/>
<c id="3"/>
<c id="4"/>
</b>
</a>
END
Fission
Split the content of a node by moving nodes to preceding or following nodes to a preceding or following node.
splitBack($$)
Move the specified node and all its preceding nodes to a newly created node preceding this node's parent and return the new node (mm July 31, 2017).
1 $old Move this node and its preceding nodes
2 $new The name of the new node.
splitBackEx($$)
Move all the nodes preceding a specified node to a newly created node preceding this node's parent and return the new node.
1 $old Move all the nodes preceding this node
2 $new The name of the new node.
splitForwards($$)
Move the specified node and all its following nodes to a newly created node following this node's parent and return the new node.
1 $old Move this node and its following nodes
2 $new The name of the new node.
splitForwardsEx($$)
Move all the nodes following a node to a newly created node following this node's parent and return the new node.
1 $old Move the nodes following this node
2 $new The name of the new node.
Put as text
Add text to the parse tree.
putFirstAsText($$)
Add a new text node first under a parent and return the new text node.
1 $node The parent node
2 $text The string to be added which might contain unparsed Xml as well as text.
putLastAsText($$)
Add a new text node last under a parent and return the new text node.
1 $node The parent node
2 $text The string to be added which might contain unparsed Xml as well as text.
putNextAsText($$)
Add a new text node following this node and return the new text node.
1 $node The parent node
2 $text The string to be added which might contain unparsed Xml as well as text.
putPrevAsText($$)
Add a new text node following this node and return the new text node
1 $node The parent node
2 $text The string to be added which might contain unparsed Xml as well as text
Break in and out
Break nodes out of nodes or push them back
breakInForwards($)
Concatenate the nodes following the start node, unwrapping nodes whose tag matches the start node and return the start node.
1 $start The start node.
Example:
p->breakInForwards
transforms:
p bp cp
xx yy zz
to:
p
xxbyyczzz
where the start node is the first p
breakInBackwards($)
Concatenate the nodes preceding the start node, unwrapping nodes whose tag matches the start node and return the start node.
1 $start The start node.
Example:
p->breakInBackwards
transforms:
p bp cp
xx yy zz
to:
p
xxbyyczzz
where the start node is the last p
breakIn($)
Concatenate the nodes following and preceding the start node, unwrapping nodes whose tag matches the start node and return the start node.
1 $start The start node.
Example:
p->breakIn
transforms:
p bp cp
xx yy zz
to:
p
xxbyyczzz
where the start node is any of the p
breakOut($@)
Lift child nodes with the specified tags under the specified parent node splitting the parent node into clones and return the cut out original node.
1 $parent The parent node
2 @tags The tags of the modes to be broken out.
Example:
p->breakOut(qw(b c))
transforms:
p
aabaacaa
to:
p bp cp
aa aa aa
Labels
Label nodes so that they can be cross referenced and linked by Data::Edit::Xml::Lint
addLabels($@)
Add the named labels to the specified node and return that node.
1 $node Node in parse tree
2 @labels Names of labels to add.
countLabels($)
Return the count of the number of labels at a node.
1 $node Node in parse tree.
getLabels($)
Return the names of all the labels set on a node.
1 $node Node in parse tree.
deleteLabels($@)
Delete the specified labels in the specified node and return that node.
1 $node Node in parse tree
2 @labels Names of the labels to be deleted
deleteAllLabels($)
Delete all the labels in the specified node and return that node.
1 $node Node in parse tree.
copyLabels($$)
Copy all the labels from the source node to the target node and return the source node.
1 $source Source node
2 $target Target node.
moveLabels($$)
Move all the labels from the source node to the target node and return the source node.
1 $source Source node
2 $target Target node.
Operators
Operator access to methods use the assign versions to avoid 'useless use of operator in void context' messages. Use the non assign versions to return the results of the underlying method call. Thus '/' returns the wrapping node, whilst '/=' does not.
opString($$)
-c : clone, -e: prettyStringEnd, -o: stringQuoted, -p : prettyString, -r : renew, -s : string, -t : tag, -z : prettyStringNumbered.
1 $node Node
2 $op Monadic operator.
Example:
-p $x
to print node $x as a pretty string.
opContents($)
@{} : content of a node.
1 $node Node.
Example:
grep {...} @$x
to search the contents of node $x
opOut($$)
>>= : Write a parse tree out on a file.
1 $node Node
2 $file File.
Example:
$x >>= *STDERR
opContext($$)
<= : Check that a node is in the context specified by the referenced array of words.
1 $node Node
2 $context Reference to array of words specifying the parents of the desired node.
Example:
$c <= [qw(c b a)]
to confirm that node $c has tag 'c', parent 'b' and grand parent 'a'.
opPutFirst($$)
+ or += : put a node or string first under a node.
1 $node Node
2 $text Node or text to place first under the node.
Example:
my $f = $a + '<p>first</p>'
opPutLast($$)
- : put a node or string last under a node.
1 $node Node
2 $text Node or text to place last under the node.
Example:
my $l = $a + '<p>last</p>'
opPutNext($$)
> : put a node or string after the current node.
1 $node Node
2 $text Node or text to place after the first node.
Example:
my $n = $a > '<p>next</p>'
opPutPrev($$)
< : put a node or string before the current node,
1 $node Node
2 $text Node or text to place before the first node.
Example:
my $p = $a < '<p>next</p>'
opBy($$)
x x= : Traverse a parse tree in post-order.
1 $node Parse tree
2 $code Code to execute against each node.
Example:
$a x= sub {say -s $_}
to print all the parse trees in a parse tree.
opGet($$)
>> : Search for a node via a specification provided as a reference to an array of words each number. Each word represents a tag name, each number the index of the previous tag or zero by default.
1 $node Node
2 $get Reference to an array of search parameters.
Example:
my $f = $a >> [qw(aa 1 bb)]
to find the first bb under the second aa under $a
opAttr($$)
% : Get the value of an attribute of this node.
1 $node Node
2 $attr Reference to an array of words and numbers specifying the node to search for.
Example:
my $a = $x % 'href'
to get the href attribute of the node at $x
opSetTag($$)
+= : Set the tag for a node.
1 $node Node
2 $tag Tag.
Example:
$a += 'tag'
to change the tag to 'tag' at the node $a
opSetId($$)
-= : Set the id for a node.
1 $node Node
2 $id Id.
Example:
$a -= 'id'
to change the id to 'id' at node $a
opWrapWith($$)
/ or /= : Wrap node with a tag, returning or not returning the wrapping node.
1 $node Node
2 $tag Tag.
Example:
$x /= 'aa'
to wrap node $x with a node with a tag of 'aa'.
opWrapContentWith($$)
* or *= : Wrap content with a tag, returning or not returning the wrapping node.
1 $node Node
2 $tag Tag.
Example:
$x *= 'aa'
to wrap the content of node $x with a node with a tag of 'aa'.
opCut($)
-- : Cut out a node.
1 $node Node.
Example:
--$x
to cut out the node $x
opUnWrap($)
++ : Unwrap a node.
1 $node Node.
Example:
++$x
to unwrap the node $x
Statistics
Statistics describing the parse tree.
count($@)
Return the count of the number of instances of the specified tags under the specified node, either by tag in array context or in total in scalar context.
1 $node Node
2 @names Possible tags immediately under the node.
countTags($)
Count the number of tags in a parse tree.
1 $node Parse tree.
countTagNames($$)
Return a hash showing the number of instances of each tag on and below the specified node.
1 $node Node
2 $count Count of tags so far.
countAttrNames($$)
Return a hash showing the number of instances of each attribute on and below the specified node.
1 $node Node
2 $count Count of attributes so far.
Debug
Debugging methods
printAttributes($)
Print the attributes of a node.
1 $node Node whose attributes are to be printed.
printAttributesReplacingIdsWithLabels($)
Print the attributes of a node replacing the id with the labels.
1 $node Node whose attributes are to be printed.
Private Methods
tree($$)
Build a tree representation of the parsed xml which can be easily traversed to look for things.
1 $parent The parent node
2 $parse The remaining parse
disconnectLeafNode($)
Remove a leaf node from the parse tree and make it into its own parse tree.
1 $node Leaf node to disconnect.
indexNode($)
Index the children of a node so that we can access them by tag and number.
1 $node Node to index.
checkParentage($)
Check the parent pointers are correct in a parse tree.
1 $x Parse tree.
checkParser($)
Check that every node has a parser.
1 $x Parse tree.
nn($)
Replace new lines in a string with N to make testing easier.
1 $s String.
Index
printAttributesReplacingIdsWithLabels
stringReplacingIdWithLabelsQuoted
Installation
This module is written in 100% Pure Perl and, thus, it is easy to read, use, modify and install.
Standard Module::Build process for building and installing modules:
perl Build.PL
./Build
./Build test
./Build install
Author
Copyright
Copyright (c) 2016-2017 Philip R Brenan.
This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself.