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).

Example 1.

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 2. 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