...XSH - XML Editing Shell

Support This Project

SF project page
Hosted on SourceForge
RSS feed


XSH2 2.1.1 Released on CPAN
Fri Feb 8 11:09:55 2008

This release is only available through CPAN. It contains several important bug and compatibility fixes and a three new XPath functions:

returns the line-number of the current node (the function was present before but was not documented)
returns a node-set which forms a span of sibling nodes starting at $start-node and ending at $end-node (these two must be siblings).
returns a node-set of sibling nodes surrounding $node. The span consists of (up to) $before-many nodes immediately preceding $node, the $node itself, and (up to) $after-many nodes immediately following $node. If the $after is not given, the value of $before is assumed.

Note: the project repository was migrated from CVS to SVN.

XSH2 2.1.0 Released
Wed Jan 3 13:57:36 2007

This release contains several feature enhancements and many bug fixes.

Incompatible Changes:

  • commands rename and map have new syntax and semantics:
    OLD (XSH 2.0.2) NEW (XSH 2.1.0)
    map { $_=uc } //text();   map { uc } //text();
    map { s/foo/bar/ } //text();   map :i { s/foo/bar/ } //text();
    map { $_='link' } //ref;   rename link //ref;

New Features:

  • XSH scripts can be "compiled" (xsh -D) into Perl scripts which start faster (see xsh --help for details)
  • XML::XSH2::Compile module provides means for efficient embedding of XSH2 scripts into Perl modules (see the module's manpage)
  • new command set simplifies creating and modifying nodes
  • new command hash simplifies hashing/grouping nodes by arbitrary keys
  • new commands change-ns-prefix and change-ns-uri add full control over namespace declarations
  • XPath functions xsh:match() (regexp matching), xsh:filename() (introspection), xsh:lookup() (hash retrieval), xsh:document() (get open document by filename), and xsh:documents() (get all open documents)
  • the interactive shell has a customizable prompt


  • the mapping expression of rename and map can be XPath
  • added save --encoding flag
  • added print --no-space (:n) flag
  • pwd and locate can return paths starting from a nearest ancestor-or-self with an ID
  • TAB-completion for default, xsh, and user-defined XPath functions
  • improved namespace handling
  • filenames of documents parsed from a file are absolute
  • many bugfixes

XSH2 for PSGML Emacs mode
Sat Sep 30 18:32:35 2006

If you, like me, use Emacs PSGML mode for editing XML documents and you are familiar with XSH2, you might find useful this tip:

The following lisp code allows you to apply an arbitrary XSH2 one-liner to any element of an XML document. Just add the code to your ~/.emacs file, open an XML file in Emacs (in psgml-mode), move the cursor inside some element, run M-x xsh-edit-element and type in a XSH2 command.

(defun xsh-edit-element (xsh-command)
  "Edit current XML element with XSH"
  (interactive "Mxsh2-command: ")
    (let ((beg (point))
	  (coding-system-for-read 'utf-8)
	  (coding-system-for-write 'utf-8))
       beg (point) 
       (concat "xsh2 -qP- " (shell-quote-argument xsh-command) " | sed 1d") t ))))

I found it indispensable e.g. for refactoring.

The commands 'map' and 'rename' are going to change
Mon Sep 25 20:40:38 2006

While working on a new release, some syntax polishing took place in the CVS version. There were two commands with which I was so unsatisfied that I decided to change them in a way that may break some of the existing scripts. Let me summarize the changes:

  • the mapping expression can also be XPath, or any other XSH2 argument expression, not just Perl
  • if Perl is used, it must be enclosed in braces, as customary in XSH2.
  • $_ is read-only and the result is collected from the expression value just like in Perl map.
  • However, --in-place (:i) flag was introduced to preserve the old behavior, when the result is taken from $_. This is useful for s///-like substitutions with Perl code.
  • map does not rename elements anymore, rename is used for that. Instead, map operates on element's content and the mapping expression may produce arbitrary nodes, not just text.

Here is how the old syntax translates to the new one:

Old syntaxNew syntax
map { $_=uc } //text();map { uc } //text();
map $_=uc //text();map { uc } //text();
map s/foo/bar/ //text();map :i { s/foo/bar/ } //text();
map { $_='link' } //refrename link //ref;

And here are some funny examples from the documentation demonstrating the gained features:

Recompute column sums in the last row of row-oriented table:

map sum(/table/row[position()<last()]/

The following commands do all about the same:

wrap --inner Z //*;

map --reverse xsh:parse(concat("<Z>",xsh:serialize(node()),"</Z>")) //*;

map xsh:parse(concat("<Z>",xsh:serialize(node()),"</Z>")) { reverse xpath('//*') };

Feel free to protest, but I'm quite happy about the result.

Compile XSH2 scripts into Perl
Sun Sep 17 18:57:58 2006

As of today, CVS version contains another nice feature. With

  $ xsh -c -D out.pl source.xsh
one can compile XSH2 source into a stand-alone Perl script which can be run with
  $ perl out.pl arguments...
The resulting Perl script still depends on XML::XSH2 modules for run-time but starts significantly faster.

A similar feature is available for Perl modules containing XSH2 code. With Module::Compile installed, one can embed XSH2 into a module like:

package Foo;
use XML::XSH2::Compile;
ls /; # any XSH2 code
no XML::XSH2::Compile;
First time the module is run, a .pmc file with pre-compiled XSH2 blocks is created. Perl automatically loads .pmc files instead of .pm when available.

News: 1-5 | 6-10 | 11-15 | 16-20 | 21-25 | 26-30 | 31-33