def id [$id | %id]* command-block or def id [$id | %id]*;




Define a new XSH subroutine named id. The subroutine may require zero or more parameters of nodelist or string type. These are declared as a whitespace-separated list of (so called) parametric variables (of nodelist or string type). The body of the subroutine is specified as a command-block. Note, that all subroutine declarations are processed during the parsing and not at run-time, so it does not matter where the subroutine is defined.

The routine can be later invoked using the call command followed by the routine name and parameters. Nodelist parameters must be given as an XPath expressions, and are evaluated just before the subroutine's body is executed. String parameters must be given as (string) expressions. Resulting node-lists/strings are stored into the parametric variables before the body is executed. These variables are local to the subroutine's call tree (see also the local command). If there is a global variable using the same name as some parametric variable, the original value of the global variable is replaced with the value of the parametric variable for the time of the subroutine's run-time.

Note that subroutine has to be declared before it is called with call. If you cannot do so, e.g. if you want to call a subroutine recursively, you have to pre-declare the subroutine using a def with no command-block. There may be only one full declaration (and possibly one pre-declaration) of a subroutine for one id and the declaration and pre-declaration has to define the same number of arguments and their types must match.

def l3 %v {
  ls %v 3; # list given nodes upto depth 3
call l3 //chapter;

Example 14. Commenting and un-commenting pieces of document

def comment
    %n      # nodes to move to comments
    $mark   # maybe some handy mark to recognize such comments
  foreach %n {
    if ( . = ../@* ) {
      echo "Warning: attribute nodes are not supported!";
    } else {
      echo "Commenting out:";
      ls .;
      local $node = "";
      ls . |> $node;
      add comment "$mark$node" replace .;

def uncomment %n $mark {
  foreach %n {
    if (. = ../comment()) { # is this node a comment node
      local $string = substring-after(.,"$mark");
      add chunk $string replace .;
    } else {
      echo "Warning: Ignoring non-comment node:";
      ls . 0;

# comment out all chapters with no paragraphs
call comment //chapter[not(para)] "COMMENT-NOPARA";

# uncomment all comments (may not always be valid!)
call uncomment //comment()[starts-with(.,"$mark")] $mark;

See Also

call, return, local