Command line xml queries for Plone configuration using xmlstarlet

One of the nice things about having declarative configuration in xml files is that you can use standard xml tools to do interesting things with them. XMLStarlet is a handy command line tool for manipulating xml. For a migration from a Plone 3 site to Plone 4 I wanted to check some things e.g. Portlets Generic Setup syntax changes explains that the use of the “for” attribute in a portlet element is deprecated. I would like to know if we have any Generic Setup xml with a portlet element which has a “for” attribute:

$ xmlstarlet sel -t -m //portlet[@for] -c . some.xml

This uses the XPath expression “//portlet[@for]” to select any >portlet< elements which have a “for” attribute. It returns a copy of any elements which match. Let’s combine this with find:

$ find . -name "*.xml" -exec xmlstarlet sel -t -m //portlet[@for] -f -n -c . -n {} \;

Here we also output the filename with “-f” and add a few newlines to make it easier to read “-n”.

You will often need to set the namespace too:

find -L . -name "*.zcml" -exec xmlstarlet sel -N x="http://namespaces.zope.org/zope" -t -m //x:vocabulary -f -n -c . -n {} \;

This can easily be adjusted for more complicated queries. The interesting parts are the XPath expression and if you want a copy of the whole matching element you can use “-c .” as above, if you want the value you can use “-v”. See http://xmlstar.sourceforge.net/doc/xmlstarlet.txt for more info.

A nice tutorial:
http://www.freesoftwaremagazine.com/articles/xml_starlet

EDIT:

To print the value of an attrtribute you can use -c “string(@attrname)”

<?xml version="1.0"?>
<phonebook>
 <contact>
  <name>John Doe</name>
  <phone type="home">555-1234</phone>
  <phone type="work" class="emphasis">555-9876</phone>
  </contact>
</phonebook>
xmlstarlet sel -t -m "//contact/phone[@type='work']" -c "string(@class)"  test.xml