Tree modification

XSH2 not only provides ways to browse and inspect the DOM tree but also many commands to modify its content by various operations, such as copying, moving, and deleting its nodes as well as creating completely new nodes or XML fragments and attaching them to it. It is quite easy to learn these commands since their names or aliases mimic their well-known filesystem analogies. On the other hand, many of these commands have two versions one of which is prefixed with a letter "x". This "x" stands for "cross", thus e.g. xcopy should be read as "cross copy". Let's explain the difference on the example of xcopy.

In a copy operation, you have to specify what nodes are to be copied and where to, in other words, you have to specify the source and the target. XSH2 is very much XPath-based so, XPath is used here to specify both of them. However, there might be more than one node that satisfies an XPath expression. So, the rule of thumb is that the "cross" variant of a command places one and every of the source nodes to the location of one and every destination node, while the plain variant works one-by-one, placing the first source node to the first destination, the second source node to the second destination, and so on (as long as there are both source nodes and destinations left).

$scratch/> $a := create "<X><A/><Y/><A/></X>";
$a/> $b := create "<X><B/><C/><B/><C/><B/></X>";
$b/> xcopy $a//A replace $b//B;
$b/> copy $b//C before $a//A;
$b/> ls $a;
<?xml version="1.0" encoding="utf-8"?>
<X><C/><A/><Y/><C/><A/></X>

$b/> ls $b;
<?xml version="1.0" encoding="utf-8"?>
<X><A/><A/><C/><A/><A/><C/><A/><A/></X>

As already indicated by the example, another issue of tree modification is the way in which the destination node determines the target location. Should the source node be placed before, after, or somewhere among the children of the resulting node? Or maybe, should it replace it completely? This information has to be given in the location argument that usually precedes the destination XPath.

Now, what happens if source and destination nodes are of incompatible types? XSH2 tries to avoid this by implicitly converting between node types when necessary. For example, if a text, comment, and attribute node is copied into, before or after an attribute node, the original value of the attribute is replaced, prepended or appended respectively with the textual content of the source node. Note however, that element nodes are never converted into text, attribute or any other textual node. There are many combinations here, so try yourself and see the results.

You may even use some more sophisticated way to convert between node types, as shown in the following example, where an element is first commented out and than again uncommented. Note, that the particular approach used for resurrecting the commented XML material works only for well-balanced chunks of XML.

Example 3. Using string variables to convert between different types of nodes

$doc := create <<EOF;
<?xml version='1.0'?>
<book>
  <chapter>
    <title>Intro</title>
  </chapter>
  <chapter>
    <title>Rest</title>
  </chapter>
</book>
EOF


# comment out the first chapter
ls //chapter[1] |> $chapter_xml;
insert comment $chapter_xml replace //chapter[1];
ls / 0;
# OUTPUT:
<?xml version="1.0"?>
<book>
<!--  <chapter>
    <title>Intro</title>
  </chapter>
-->
  <chapter>
    <title>Rest</title>
  </chapter>
</book>


# un-comment the chapter
$comment = string(//comment()[1]);
insert chunk $comment replace //comment()[1];
ls / 0;
# OUTPUT:
<?xml version="1.0"?>
<book>
  <chapter>
    <title>Intro</title>
  </chapter>

  <chapter>
    <title>Rest</title>
  </chapter>
</book>

Related topics

change-ns-prefix

change namespace prefix (EXPERIMENTAL)

change-ns-uri

change namespace URI (EXPERIMENTAL)

clone

clone a given document

copy

copy nodes (in the one-to-one mode)

declare-ns

create a special attribute declaring an XML namespace (EXPERIMENTAL)

edit

Edit parts of a XML document in a text editor.

edit-string

Edit a string or variable in a text editor.

expression

expression argument type

hash

index selected nodes by some key value

insert

create a node in on a given target location

location

relative destination specification (such as after, before, etc.)

map

transform node value/data using Perl or XPath expression

move

move nodes (in the one-to-one mode)

node-type

node type specification (such as element, attribute, etc.)

normalize

normalizes adjacent textnodes

process-xinclude

load and insert XInclude sections

remove

remove given nodes

rename

quickly rename nodes with in-line Perl code

set

create or modify document content (EXPERIMENTAL)

set-dtd

set document's DTD declaration

set-enc

set document's charset (encoding)

set-ns

set namespace of the current node (EXPERIMENTAL)

set-standalone

set document's standalone flag

sort

sort a given node-list by given criteria

strip-whitespace

strip leading and trailing whitespace

wrap

wrap given nodes into elements

wrap-span

wrap spans of nodes into elements

xcopy

copy nodes (in the all-to-every mode)

xinsert

create nodes on all target locations

xmove

move nodes (in the all-to-every mode)

xpath

XPath expression

xslt

compile a XSLT stylesheet and/or transform a document with XSLT

xupdate

apply XUpdate commands on a document