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.
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 |> $chapter_xml; add comment $chapter_xml replace //chapter; 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()); add chunk $comment replace //comment(); ls / 0; # OUTPUT: <?xml version="1.0"?> <book> <chapter> <title>Intro</title> </chapter> <chapter> <title>Rest</title> </chapter> </book>