Take the 2-minute tour ×

I'm making an SCons file for building Docbook documentation. In order to trace dependencies I would like some way to resolve catalog file lookups to an absolute path to a file.

So say I have a bit of Docbook XML :


    <title>Docbook example document</title>

    <xi:include href="file:///common/logo.xml"

  <xi:include href="chap1/chap1.xml"/>
  <xi:include href="chap2/chap2.xml"/>
  <xi:include href="chap3/chap3.xml"/>
  <xi:include href="chap4/chap4.xml"/>


and a catalog.xml file :

<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">

    rewritePrefix="file:///home/kst/svn/TOOLS/Docbook/stylesheet/" />

    rewritePrefix="file:///home/kst/svn/TOOLS/Docbook/common/" />

  <nextCatalog  catalog="/etc/xml/catalog" />


Getting the xinclude href string is no problem using lxml but I'm stuck there. What I need is some way to get the absolute filename that file:///common/logo.xml resolves to (in this case /home/kst/svn/TOOLS/Docbook/common/logo.xml) from the catalog file. It needs to be some kind of Python code so I can use it in my SConstruct file without too much hassle.

Any help is appreciated.

share|improve this question
add comment

1 Answer

up vote 0 down vote accepted

Lxml uses the catalog support from libxml2. Use the environment variable XML_CATALOG_FILES to provide a list of catalogs (you could set this from python as well, using os.environ), or, if this variable is not present, it checks for the existence of /etc/xml/catalog (can't use this one on windows of course).

An alternative would be to use a custom URI resolver. You can find more information in the lxml docs

EDIT: apparently, the question was not about the actual xinclude processing, which works, but about a way to "query" the catalog, or ask it for the actual filenames that would be used for the inclusions.

Lxml (at least currently) has no API to do that. The underlying libxml2 library does support this, however, and the "original" libxml2 python bindings allow you to do this (easy documentation is lacking though, the docstrings in the source code of the libxml2 help, however). So, although this module is not nearly as nice to use than lxml, it seems to be your best bet. Example which seems to work:

>>> import libxml2
>>> libxml2.loadCatalog('catalog.xml')
>>> print libxml2.catalogResolveURI('file:///common/logo.xml')
share|improve this answer
I've been trying to do this but I haven't been able to get it to work. Note that I am not interested in validating my document but in getting the filenames of any xml files the document includes and therefore depends on. –  Kevin Steffensen Aug 29 '11 at 12:25
As far as I know, it does not only apply to validating, but also to xinclude resolving. How dit you try it? Did you get any specific errors? –  Steven Aug 29 '11 at 15:16
@Kevin Steffensen: I just tested a simple example myself, and xinclude with a catalog seems to work just fine? It would seem that there is something wrong with either the file location, or your xpointer (which would need an id attribute with the value of "logo", I used xml:id="logo" in my test. You could maybe try without the xpointer to check whether you can include the whole document first, then go on with the xpointer) –  Steven Aug 29 '11 at 18:45
Actual parsing of the document using xinclude and xpointer works fine. But I want to scan some xml file and find out the filenames of the files that xml file depends on and this is where I fail. I've tried iterating over the <xi:include> elements and grabbing the href attribute. This works but gives me references like 'file:///common/example.xml'. I need to change this reference into an actual filename using the information in my catalog somehow. –  Kevin Steffensen Aug 29 '11 at 19:51
Ah, you mean you do NOT want to process the xincludes and actually include the content, only look up the actual filenames via the catalog? (Although I think libxml2 supports that, lxml has no api to do that as far as I know) –  Steven Aug 29 '11 at 20:05
show 2 more comments

Your Answer


