Welcome, guest | Sign In | My Account | Store | Cart

This code shows how to load a stylesheet from "virtual" URLs, by detecting a special URL scheme.

Python, 53 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
from xml.xslt.Processor import Processor
from xml.xslt.StylesheetReader import StylesheetReader

class StylesheetFromDict(StylesheetReader):
    "A stylesheet reader that loads XSLT stylesheets from a python dictionary"

    def __init__(self, styles, *args):
        "Remember the dict we want to load the stylesheets from"
        apply(StylesheetReader.__init__, (self,) + args)
        self.styles = styles
        self.__myargs = args

    def __getinitargs__(self):
        "Return init args for clone()"
        return (self.styles,) + self.__myargs

    def fromUri(self, uri, baseUri='', ownerDoc=None, stripElements=None):
        "Load stylesheet from a dict"
        parts = uri.split(':', 1)
        if parts[0] == 'internal' and self.styles.has_key(parts[1]):
            # load the stylesheet from the internal repository (our dict)
            return StylesheetReader.fromString(self, self.styles[parts[1]],
                baseUri, ownerDoc, stripElements)
        else:
            # revert to normal behaviour
            return StylesheetReader.fromUri(self, uri,
                baseUri, ownerDoc, stripElements)

if __name__ == "__main__":
    # the sample stylesheet repository
    internal_stylesheets = {
        'second-author.xsl': """
            <person xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xsl:version="1.0">
            <xsl:value-of select="books/book/author[2]"/>
            </person>
        """
    }

    # the sample document, referring to an "internal" stylesheet
    xmldoc = """
      <?xml-stylesheet href="internal:second-author.xsl" type="text/xml"?>
      <books>
        <book title="Python Essential Reference">
          <author>David M. Beazley</author>
          <author>Guido van Rossum</author>
        </book>
      </books>
    """

    # create XSLT processor and run it
    processor = Processor()
    processor.setStylesheetReader(StylesheetFromDict(internal_stylesheets))
    print processor.runString(xmldoc)

If you get a lot of XML documents from third parties (via FTP, HTTP or some other means), there is the problem that the document was created in THEIR environment and now needs to be processed in YOUR environment. Especially if the document refers to external files in the file system of the remote host, this paths often do not make sense on your local host. One common technique to refer to external documents is to use public URLs accessible via the internet, but that of course incurs a lot of overhead (you need to fetch the stylesheet from the remote server) and some risk (what if the remote server is down).

Another approach is to use private URL schemes, like "stylesheet:layout.xsl". Those need to be resolved to real, existing URLs, which the above code does for XSLT processing. We show how to use a hook offered by 4Suite, a Python XSLT engine, to refer to stylesheets that way in a xml-stylesheet processing instruction (see http://www.w3.org/TR/xml-stylesheet/).

The same technique can be used to load the stylesheet from a database, or to return a locally cached stylesheet previously fetched from a remote URL.

The output of the test code is: <?xml version='1.0' encoding='UTF-8'?> <person>Guido van Rossum</person>

To run the code, you need Python 2.0 (http://www.python.org/) and 4Suite 0.10.2 (http://www.4suite.org/), or a higher version.

3 comments

Uche Ogbuji 19 years, 5 months ago  # | flag

Updates accommodating API changes. See the following document for updates to this recipe, accommodating the updated 4Suite APIs:

http://uche.ogbuji.net/tech/akara/pyxml/xslt-resolver/

Uche Ogbuji 16 years, 10 months ago  # | flag

Updates accommodating API changes. I just noticed this stale link. The not now resides at:

http://uche.ogbuji.net/tech/akara/nodes/2003-01-01/xslt-resolver

--Uche

a 11 years, 7 months ago  # | flag

apply() is deprecated. apply(StylesheetReader.__init__, (self,) + args) should be changed to StylesheetReader.__init__(self, *args)