Tree modification

XSH provides mechanisms not only to browse and inspect the DOM tree but also to modify its content by providing commands for copying, moving, and deleting its nodes as well as adding completely new nodes or XML fragments 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.

When you copy, you have to specify what are you copying and where are you copying to, so you have to specify the source and the target. XSH 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).

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

xsh> 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 into the resulting node? 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? XSH 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 sofisticated 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 4. Using string variables to convert between different types of nodes

create doc <<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;
add 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]);
add 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 Argument Types and Commands

clone

clone a given document

copy

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

expression

string-like expression

insert

create a node in on a given target location

location

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

map

quickly modify node value/data using Perl code

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-enc

set document's charset (encoding)

set-standalone

set document's standalone flag

strip-whitespace

strip leading and trailing whitespace

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

transform document with XSLT

xupdate

apply XUpdate commands on a document