XML technologies

Namespaces with "xmlllint --xpath" and with "xmlllint --shell"

Jean-François Perrot

  1.  The problem
  2. Use xmllint --shell
  3. Namespaces with xmllint --shell

  1.  The problem

    We have been unsing the xmllint --xpath command as a lightweight tool to experiment with XPath expressions.
    This technique fails dismally when applied to XML files with namespaces!

    For instance, to extract from our BookReview file the <xdc:title> element, the only possible turnaround is
    xmllint exnmsb.html --xpath "//*[local-name()='title' and namespace-uri()='http://www.xml.com/books']"
    which indeed yields
    <xdc:title style="font-family: sans-serif;">XML: A Primer</xdc:title>

    Our command takes as arguments a filename and an XPath expression.
    Since full URIs are much too cumbersome (see the example above), the only practical way to write the expression will be to use prefixes.
    But how can we declare the correspondence between those "local" prefixes and the namespace URIs of the XML file ?

    In Java this is achieved through a NamespaceContext.
    With xmllint --path it is simply not possible !

  2. Use xmllint --shell

    The --shell option illustrates the analogy between an XML tree and the tree of Unix directories.
    See e.g. Playing With XPath Expressions in The xmllint Shell to further illustrate the use of this command.

    Examples (continued from XPath course notes) :

    jfp$ xmllint --shell Garage.xml
    / >                                   
    note the new "prompt" that tells us that we are at the root
    / > xpath /Garage/Car/Engine/Ignition  without quotes
    Object is a Node Set :
    Set contains 3 nodes:
    1  ELEMENT Ignition
    2  ELEMENT Ignition
    3  ELEMENT Ignition
    / >
    / > xpath /Garage/Car/@make
    Object is a Node Set :
    Set contains 3 nodes:
    1  ATTRIBUTE make
        TEXT
          content=Citro#C3#ABn
    2  ATTRIBUTE make
        TEXT
          content=Renault
    3  ATTRIBUTE make
        TEXT
          content=Toyota
    / >
    / > xpath count(/Garage/Car/Engine)
    Object is a number : 3
    / >


    ... all the above examples may be played in this setting, e.g.
    / > xpath //Transmission[@gear_nb = 5]/../Body/@color
    Object is a Node Set :
    Set contains 2 nodes:
    1  ATTRIBUTE color
        TEXT
          content=blue
    2  ATTRIBUTE color
        TEXT
          content=white
    / >


    Changing the evaluation context via cd (analogy node <--> directory)

    / > cd Garage
    Garage >            
    note the change of prompt from '/' to 'Garage'
    Garage > xpath Car/Body[@color = 'blue']
    Object is a Node Set :
    Set contains 1 nodes:
    1  ELEMENT Body
        ATTRIBUTE color
          TEXT
            content=blue
    Garage >

    Garage > cd Car
    Car is a 3 Node Set        cd
    must be deterministic !
    Garage > cd Car/Body[@color = 'blue']
    Body >
    Body > xpath *
    Object is a Node Set :
    Set contains 1 nodes:
    1  ELEMENT Hood
    Body >
    etc...exit via Ctrl-D


  3. Namespaces with xmllint --shell

    As opposed to the --xpath option, the --shell option does provide a command to specify (prefix, URI) pairs :
    setns prefix=URI (one at a time)

    Let us take up again our favorite example...
    jfp$ xmllint --shell ../Namespaces/exnmsb.html
    / > setns bk=http://www.xml.com/books
    / >
    / > xpath //bk:title
    Object is a Node Set :
    Set contains 1 nodes:
    1  ELEMENT xdc:title
        ATTRIBUTE style
          TEXT
            content=font-family: sans-serif;
    / >
    / > setns h=http://www.w3.org/1999/xhtml
    empty prefix not allowed
    / > xpath //h:title
    Object is a Node Set :
    Set contains 1 nodes:
    1  ELEMENT title
    / > xpath //bk:title/text()
    Object is a Node Set :
    Set contains 1 nodes:
    1  TEXT
        content=XML: A Primer
    / > xpath //h:title/text()
    Object is a Node Set :
    Set contains 1 nodes:
    1  TEXT
        content=Book Review
    / >

    That's the way things are...