Package: xdv
ContentsIntroductionInstallationRules file syntax<replace /><copy /><append />and<prepend /><before />and<after /><drop />Order of rule executionBehaviour if theme or content is not matchedAdvanced usageConditional rulesIncluding external contentModifying the theme on the flyInline XSL directivesXIncludeCompilationAbsolute prefixTesting the compiled themeCompiling the theme in Python codeDeploymentPloneWSGInginxIncluding external contentVarnishApacheChangelog0.3 - 2010-05-290.3rc2 - 2010-05-250.3rc1 - 2010-05-23IntroductionXDV is an implementation of theDeliveranceconcept using pure XSLT. In
short, it is a way to apply a style/theme contained in a static HTML web page
(usually with related CSS, JavaScript and image resources) to a dynamic
website created using any server-side technology.Consider a scenario where you have a dynamic website, to which you want to
apply a theme built by a web designer. The web designer is not familiar with
the technology behind the dynamic website, and so has supplied a “static HTML”
version of the site. This consists of an HTML file with more-or-less semantic
markup, one or more style sheets, and perhaps some other resources like
images or JavaScript files.Using XDV, you could apply this theme to your dynamic website as follows:Identify the placeholders in the theme file that need to be replaced with
dynamic elements. Ideally, these should be clearly identifiable, for
example with a unique HTMLidattribute.Identify the corresponding markup in the dynamic website. Then write a
“replace” or “copy” rule using XDV’s rules syntax that replaces the theme’s
static placeholder with the dynamic content.Identify markup in the dynamic website that should be copied wholesale into
the theme. CSS and JavaScript links in the<head />are often treated
this way. Write an XDV “append” or “prepend” rule to copy these elements
over.Identify parts of the theme and/or dynamic website that are superfluous.
Write an XDV “drop” rule to remove these elements.The rules file is written using a simple XML syntax. Elements in the theme
and “content” (the dynamic website) can be identified using CSS3 or XPath
selectors.Once you have a theme HTML file and a rules XML file, you compile these using
the XDV compiler into a single XSLT file. You can then deploy this XSLT file
with your application. An XSLT processor (such as mod_transform in Apache)
will then transform the dynamic content from your website into the themed
content your end users see. The transformation takes place on-the-fly for
each request.Bear in mind that:You never have to write, or even read, a line of XSLT (unless you want to).The XSLT transformation that takes place for each request is very fast.Static theme resources (like images, stylesheets or JavaScript files) can
be served from a static webserver, which is normally much faster than
serving them from a dynamic application.You can leave the original theme HTML untouched, with makes it easier to
re-use for other scenarios. For example, you can stitch two unrelated
applications together by using a single theme file with separate rules
files. This would result in two compiled XSLT files. You could use location
match rules or similar techniques to choose which one to invoke for a given
request.We will illustrate how to set up XDV for deployment below.InstallationTo install XDV, you should install thexdvegg. You can do that usingeasy_install,piporzc.buildout. For example, usingeasy_install(ideally in avirtualenv):$ easy_install -U xdvIf usingzc.buildout, you can use the followingbuildout.cfgas a
starting point. This will ensure that the console scripts are installed,
which is important if you need to execute the XDV compiler manually:[buildout]
parts =
    xdv

[xdv]
recipe = zc.recipe.egg
eggs = xdvNote thatlxmlis a dependency ofxdv, so you may need to install the
libxml2 and libxslt development packages in order for it to build. On
Debian/Ubuntu you can run:$ sudo apt-get install libxslt1-devOn some operating systems, notably Mac OS X, installing a “good”lxmlegg
can be problematic, due to a mismatch in the operating system versions of thelibxml2andlibxsltlibraries thatlxmluses. To get around that,
you can compile a staticlxmlegg using the following buildout recipe:[buildout]
# lxml should be first in the parts list
parts =
    lxml
    xdv

[lxml]
recipe = z3c.recipe.staticlxml
egg = lxml
libxml2-url = http://xmlsoft.org/sources/libxml2-2.7.6.tar.gz
libxslt-url = http://xmlsoft.org/sources/libxslt-1.1.26.tar.gz

[xdv]
recipe = zc.recipe.egg
eggs = xdvOnce installed, you should findxdvcompilerandxdvrunin yourbindirectory.Rules file syntaxThe rules file, conventionally calledrules.xml, is rooted in a tag
called<rules />:<?xml version="1.0" encoding="UTF-8"?>
<rules xmlns="http://namespaces.plone.org/xdv"
       xmlns:css="http://namespaces.plone.org/xdv+css">

       ...

</rules>Here we have defined two namespaces: the default namespace is used for rules
and XPath selectors. Thecssnamespace is used for CSS3 selectors. These
are functionally equivalent. In fact, CSS selectors are replaced by the
equivalent XPath selector during the pre-processing step of the compiler.
Thus, they have no performance impact.XDV supports complex CSS3 and XPath selectors, including things like thenth-childpseudo-selector. You are advised to consult a good reference
if you are new to XPath and/or CSS3.The following elements are allowed inside the<rules />element:<replace />Used to replace an element in the theme entirely with an element in the
content. For example:<replace theme="/html/head/title" content="/html/head/title"/>The (near-)equivalent using CSS selectors would be:<replace css:theme="title" css:content="title"/>The result of either is that the<title />element in the theme is
replaced with the<title />element in the (dynamic) content.<copy />Used to replace the contents of a placeholder tag with a tag from the
theme. For example:<copy css:theme="#main" css:content="#portal-content > *" />This would replace any placeholder content inside the element with idmainin the theme with all children of the element with idportal-contentin the content. The usual reason for using<copy />instead of<replace />, is that the theme has CSS styles or other
behaviour attached to the target element (with idmainin this case).<append />and<prepend />Used to copy elements from the content into an element in the theme,
leaving existing content in place.<append />places the matched
content directly before the closing tag in the theme;<prepend />places
it directly after the opening tag. For example:<append theme="/html/head" content="/html/head/link" />This will copy all<link />elements in the head of the content into
the theme.As a special case, you can copy individualattributesfrom a content
element to an element in the theme using<prepend />:<prepend theme="/html/body" content="/html/body/@class" />This would copy theclassattribute of the<body />element in
the content into the theme (replacing an existing attribute with the
same name if there is one).<before />and<after />These are equivalent to<append />and<prepend />, but place
the matched content before or after the matched theme element, rather
than immediately inside it. For example:<before css:theme=”#content” css:content=”#info-box” />This would place the element with idinfo-boxfrom the content
immediately before the element with idcontentin the theme. If we
wanted the box below the content instead, we could do:<after css:theme="#content" css:content="#info-box" /><drop />Used to drop elements from the theme or the content. This is the only
element that accepts eitherthemeorcontentattributes (or theircss:equivalents), but not both:<drop css:content="#portal-content .about-box" />
<copy css:theme="#content" css:content="#portal-content > *" />This would copy all children of the element with idportal-contentin
the theme  into the element with idcontentin the theme, but only
after removing any element with classabout-boxinside the content
element first. Similarly:<drop theme="/html/head/base" />Would drop the<base />tag from the head of the theme.Order of rule executionIn most cases, you should not care too much about the inner workings of the
XDV compiler. However, it can sometimes be useful to understand the order
in which rules are applied.<before />rules are always executed first.<drop />rules are executed next.<replace />rules are executed next, provided no<drop />rule was
applied to the same theme node.<prepend />,<copy />and<append />rules execute next,
provided no<replace />rule was applied to the same theme node.<after />rules are executed last.Behaviour if theme or content is not matchedIf a rule does not match the theme (whether or not it matches the content),
it is silently ignored.If a<replace />rule matches the theme, but not the content, the matched
element will be dropped in the theme:<replace css:theme="#header" content="#header-element" />Here, if the element with idheader-elementis not found in the content,
the placeholder with idheaderin the theme is removed.Similarly, the contents of a theme node matched with a<copy />rule will
be dropped if there is no matching content. Another way to think of this is
that if no content node is matched, XDV uses an empty nodeset when copying or
replacing.If you want the placeholder to stay put in the case of a missing content node,
you can make this a conditional rule:<replace css:theme="#header" content="#header-element" if-content="" />See below for more details on conditional rules.Advanced usageThe simple rules above should suffice for most use cases. However, there are
a few more advanced tools at your disposal, should you need them.Conditional rulesSometimes, it is useful to apply a rule only if a given element appears or
does not appear in the markup. Theif-contentattribute can be used with
any rule to make it conditional.if-contentshould be set an XPath expression. You can also usecss:if-contentwith a CSS3 expression. If the expression matches a node
in the content, the rule will be applied:<copy css:theme="#portlets" css:content=".portlet"/>
<drop css:theme="#portlet-wrapper" if-content="not(//*[@class='portlet'])"/>This will copy all elements with classportletinto theportletselement. If there are no matching elements in the content we drop theportlet-wrapperelement, which is presumably superfluous.Here is another example using CSS selectors:<copy css:theme="#header" css:content="#header-box > *"
      css:if-content="#personal-bar"/>This will copy the children of the element with idheader-boxin the
content into the element with idheaderin the theme, so long as an
element with idpersonal-baralso appears somewhere in the content.Above, we also saw the special case of an emptyif-content(which also
works with an emptycss:if-content). This is a shortcut that means “use
the expression in thecontentorcss:content`attribute as the
condition”. Hence the following two rules are equivalent:<copy css:theme="#header" css:content="#header-box > *"
      css:if-content="#header-box > *"/>
<copy css:theme="#header" css:content="#header-box > *"
      css:if-content=""/>If multiple rules of the same type match the same theme node but have
differentif-contentexpressions, they will be combined as an
if..else if…else block:<copy theme="/html/body/h1" content="/html/body/h1/text()"
      if-content="/html/body/h1"/>
<copy theme="/html/body/h1" content="//h1[@id='first-heading']/text()"
      if-content="//h1[@id='first-heading']"/>
<copy theme="/html/body/h1" content="/html/head/title/text()" />These rules all attempt to fill the text in the<h1 />inside the body.
The first rule looks for a similar<h1 />tag and uses its text. If that
doesn’t match, the second rule looks for any<h1 />with idfirst-heading, and uses its text. If that doesn’t match either, the
final rule will be used as a fallback (since it has noif-content),
taking the contents of the<title />tag in the head of the content
document.Including external contentNormally, thecontentattribute of any rule selects nodes from the
response being returned by the underlying dynamic web server. However, it is
possible to include content from a different URL using thehrefattribute
on any rule (other than<drop />). For example:<append css:theme="#left-column" css:content="#portlet" href="/extra.html"/>This will resolve the URL/extra.html, look for an element with idportletand then append to to the element with idleft-columnin the
theme.The inclusion can happen in one of three ways:Using the XSLTdocument()function. This is the default, but it can
be explicitly specified by adding an attributemethod="document"to the
rule element. Whether this is able to resolve the URL depends on how and
where the compiled XSLT is being executed:<append css:theme="#left-column" css:content="#portlet"
        href="/extra.html" method="document" />Via a Server Side Include directive. This can be specified by setting themethodattribute tossi:<append css:theme="#left-column" css:content="#portlet"
        href="/extra.html" method="ssi"/>The output will look something like this:<!--# include wait="yes" virtual="/extra.html?;filter_xpath=//*[@id%20=%20'portlet']" -->This SSI instruction would need to be processed by a fronting web server
such as Apache or nginx. Also note the;filter_xpathquery string
parameter. Since we are deferring resolution of the referenced document
until SSI processing takes place (i.e. after the compiled XDV XSLT transform
has executed), we need to ask the SSI processor to filter out elements in
the included file that we are not interested in. This requires specific
configuration. An example for nginx is included below.For simple SSI includes of a whole document, you may omit thecontentselector from the rule:<append css:theme="#left-column" href="/extra.html" method="ssi"/>The output then renders like this:<!--# include wait="yes" virtual="/extra.html" -->Via an Edge Side Includes directive. This can be specified by setting themethodattribute toesi:<append css:theme="#left-column" css:content="#portlet"
        href="/extra.html" method="esi"/>The output is similar to that for the SSI mode:<esi:include src="/extra.html?;filter_xpath=//*[@id%20=%20'portlet']"></esi:include>Again, the directive would need to be processed by a fronting server, such
as Varnish. Chances are an ESI-aware cache server would not support
arbitrary XPath filtering. If the referenced file is served by a dynamic
web server, it may be able to inspect the;filter_xpathparameter and
return a tailored response. Otherwise, if a server that can be made aware
of this is placed in-between the cache server and the underlying web server,
that server can perform the necessary filtering.For simple ESI includes of a whole document, you may omit thecontentselector from the rule:<append css:theme="#left-column" href="/extra.html" method="esi"/>The output then renders like this:<esi:include src="/extra.html"></esi:include>Modifying the theme on the flySometimes, the theme is almost perfect, but cannot be modified, for example
because it is being served from a remote location that you do not have access
to, or because it is shared with other applications.XDV allows you to modify the theme using “inline” markup in the rules file.
You can think of this as a rule where the matchedcontentis explicitly
stated in the rules file, rather than pulled from the response being styled.For example:<xdv:rules
    xmlns:xdv="http://namespaces.plone.org/xdv"
    xmlns:css="http://namespaces.plone.org/xdv+css"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    >

    <xdv:append theme="/html/head">
        <style type="text/css">
            /* From the rules */
            body > h1 { color: red; }
        </style>
    </xdv:append>

</xdv:rules>Notice how we have placed the rules in an explicitxdvnamespace, so that
we can write the “inline” HTML without a namespace prefix.In the example above, the<append />rule will copy the<style />attribute and its contents into the<head />of the theme. Similar rules
can be constructed for<copy />,<replace />,<prepend />,<before />or<after />.It is even possible to insert XSLT instructions into the compiled theme in
this manner. Having declared thexslnamespace as shown above, we can do
something like this:<xdv:replace css:theme="#details">
    <dl id="details">
        <xsl:for-each css:select="table#details > tr">
            <dt><xsl:copy-of select="td[1]/text()"/></dt>
            <dd><xsl:copy-of select="td[2]/node()"/></dd>
        </xsl:for-each>
    </dl>
</xdv:replace>Note that css expressions are converted to “placeless” XPath expressions,
socss:select="table#details> tr"converts toselect="//table[@id='details]/tr". This means it would not be possible to
usecss:select="td:first-child> *"as you want a relative selector here.
You can, of course, just use a manual XPath in aselectattribute instead.Inline XSL directivesYou may supply inline XSL directives in the rules to tweak the final output,
for instance to strip space from the output document use:<rules xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:strip-space elements="*" />

</rules>Note: this may effect the rendering of the page on the browser.To use a strict doctype:<xsl:output
    doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
    doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"/>XIncludeYou may wish to re-use elements of your rules file across multiple themes.
This is particularly useful if you have multiple variations on the same theme
used to style different pages on a particular website.Rules files may be included using the XInclude protocol.Inclusions use standard XInclude syntax. For example:<rules
    xmlns="http://namespaces.plone.org/xdv"
    xmlns:css="http://namespaces.plone.org/xdv+css"
    xmlns:xi="http://www.w3.org/2001/XInclude">

    <xi:include href="standard-rules.xml" />

</rules>CompilationOnce you have written your rules file, you need to compile it to an XSLT for
deployment. In some cases, you may have an application server that does this
on the fly, e.g. if you are using thecollective.xdvpackage with Plone.
For deployment to a web server like Apache or nginx, however, you will need
to perform this step manually.The easiest way to invoke the XDV compiler is via thexdvcompilercommand
line script which is installed with thexdvegg. To see its help output,
do:$ bin/xdvcompiler --helpTo run the compiler withrules.xmloperating ontheme.html:$ bin/xdvcompiler rules.xml theme.htmlThis will print the compiled XSLT file to the standard output. You can save
it to a file instead using:$ bin/xdvcompiler -o theme.xsl rules.xml theme.htmlThe following command line options are available:Use-pto pretty-print the output for improved readability. There is a
risk that this could alter rendering in the browser, though, as browsers
are sensitive to some kinds of whitespace.Use-ato set an absolute prefix - see below.Use-ito set the default external file inclusion mode to one ofdocument,ssioresi.Use--traceto output trace logging during the compilation step. This
can be helpful in debugging rules.Check the output of the--helpoption for more details.Absolute prefixThe compiler can be passed an “absolute prefix”. This is a string that will be
prefixed to anyrelativeURL referenced an image, link or stylesheet in the
theme HTML file, before the theme is passed to the compiler. This allows a
theme to be written so that it can be opened and views standalone on the
filesystem, even if at runtime its static resources are going to be served
from some other location.For example, say the theme is written with relative URLs for images and
external resources, such as<imgsrc="images/foo.jpg"/>. When the
compiled theme is applied to a live site, this is unlikely to work for
any URL other than a sibling of theimagesfolder.Let’s say the theme’s static resources are served from a simple web server
and made available under the directory/static. In this case, we can
set an absolute prefix of/static. This will modify the<img />tag
in the compiled theme so that it becomes an absolute path that will work for
any URL:<imgsrc="/static/images/foo.jpg"/>Testing the compiled themeTo test the compiled theme, you can apply it to a static file representing
the content. The easiest way to do this is via thexdvrunscript:$ bin/xdvrun theme.xsl content.htmlThis will print the output to the standard output. You can save it to a file
instead with:$ bin/xdvrun -o output.html theme.xsl content.htmlFor testing, you can also compile and run the theme in one go, by using the-r(rules) and-t(theme) arguments toxdvrun:$ bin/xdvrun -o output.html -r rules.xml -t theme.html content.htmlTo see the built-in help for this command, run:$ bin/xdvrun --helpCompiling the theme in Python codeYou can run the XDV compiler from Python code using the following helper
function:>>> from xdv.compiler import compile_themeThis method takes the following arguments:rulesis the rules file, given either as a file name or a string with
the file contents.themeis the theme file, given either as a file name or a string with
the file contentsextrais an optional XSLT file with XDV extensions, given as a URI
(depracated, use inline xsl in the rules instead)csscan be set to False to disable CSS syntax support (providing a
moderate speed gain)xincludecan be set toFalseto enable XInclude support (at a
moderate speed cost). If enabled, XInclude syntax can be used to split the
rules file into multiple, re-usable fragments.absolute_prefixcan be set an string to be used as the “absolute prefix”
for relative URLs - see above.updatecan be set toFalseto disable the automatic update support
for the old Deliverance 0.2 namespace (for a moderate speed gain)tracecan be set to True to enable compiler trace informationincludemodecan be set to ‘document’, ‘esi’ or ‘ssi’ to change the way
in which includes are processedparsercan be set to an lxml parser instance; the default is an
HTMLParsercompiler_parser`can be set to an lxml parser instance; the default is a
XMLParserrules_parsercan be set to an lxml parser instance; the default is a
XMLParse.The parser parameters may be used to add custom resolvers for external content
if required. See thelxmldocumentation for
details.compile_theme()returns an XSLT document inlxml’sElementTreeformat. To set up a transform representing the theme and rules, you can do:from lxml import etree
from xdv.compiler import compile_theme

absolute_prefix = "/static"

rules = "rules.xml"
theme = "theme.html"

compiled_theme = compile_theme(rules, theme,
                               absolute_prefix=absolute_prefix)

transform = etree.XSLT(compiled_theme)You can now use this transformation:content = etree.parse(some_content)
transformed = transform(content)

output = etree.tostring(transformed)Please see thelxmldocumentation for more details.DeploymentBefore it can be used, the deployed theme needs to be deployed to a proxying
web server which can apply the XSLT to the response coming back from another
web application.In theory, any XSLT processor will do. In practice, however, most websites
do not produce 100% well-formed XML (i.e. they do not conform to the XHTML
“strict” doctype). For this reason, it is normally necessary to use an XSLT
processor that will parse the content using a more lenient parser with some
knowledge of HTML. libxml2, the most popular XML processing library on Linux
and similar operating systems, contains such a parser.PloneIf you are working with Plone, the easiest way to use XDV is via thecollective.xdvadd-on. This
provides a control panel for configuring the XDV rules file, theme and
other options, and hooks into a transformation chain that executes after
Plone has rendered the final page to apply the XDV transform.Even if you intend to deploy the compiled theme to another web server,collective.xdvis a useful development tool: so long as Zope is in
“development mode”, it will re-compile the theme on the fly, allowing you
to make changes to theme and rules on the fly. It also provides some tools
for packaging up your theme and deploying it to different sites.WSGIIf you are using a WSGI stack, you can use thedv.xdvservermiddleware to apply an XDV
theme. This supports all the core XDV options, and can be configured to
either re-compile the theme on the fly (useful for development), or compile
it only once (useful for deployment.)It is also possible to use this with the Pasteproxymiddleware to
create a standalone XDV proxy for any site. See thedv.xdvserverdocumentation for details.nginxTo deploy an XDV theme to thenginxweb server, you
will need to compile nginx with a special version of the XSLT module that
can (optionally) use the HTML parser from libxml2.In the future, the necessary patches to enable HTML mode parsing will
hopefully be part of the standard nginx distribution. In the meantime,
they are maintained in thehtml-xsltproject.Using a properly patched nginx, you can configure it with XSLT support like
so:$ ./configure --with-http_xslt_moduleIf you are using zc.buildout and would like to build nginx, you can start
with the following example:[buildout]
parts =
    ...
    nginx

...

[nginx]
recipe = zc.recipe.cmmi
url = http://html-xslt.googlecode.com/files/nginx-0.7.65-html-xslt-2.tar.gz
extra_options =
    --conf-path=${buildout:directory}/etc/nginx.conf
    --sbin-path=${buildout:directory}/bin
    --error-log-path=${buildout:directory}/var/log/nginx-error.log
    --http-log-path=${buildout:directory}/var/log/nginx-access.log
    --pid-path=${buildout:directory}/var/nginx.pid
    --lock-path=${buildout:directory}/var/nginx.lock
    --with-http_stub_status_module
    --with-http_xslt_moduleIf libxml2 or libxslt are installed in a non-standard location you may need to
supply the--with-libxml2=<path>and--with-libxslt=<path>options.
This requires that you set an appropriateLD_LIBRARY_PATH(Linux / BSD) orDYLD_LIBRARY_PATH(Mac OS X) environment variable when running nginx.For theming a static site, enable the XSLT transform in the nginx
configuration as follows:location / {
    xslt_stylesheet /path/to/compiled-theme.xsl;
    xslt_html_parser on;
    xslt_types text/html;
}nginx may also be configured as a transforming proxy server:location / {
    xslt_stylesheet /path/to/compiled-theme.xsl;
    xslt_html_parser on;
    xslt_types text/html;
    rewrite ^(.*)$ /VirtualHostBase/http/localhost/Plone/VirtualHostRoot$1 break;
    proxy_pass http://127.0.0.1:8080;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-XDV "true";
    proxy_set_header Accept-Encoding "";
}Removing the Accept-Encoding header is sometimes necessary to prevent the
backend server compressing the response (and preventing transformation). The
response may be compressed in nginx by settinggzip on;- see thegzip
module documentationfor
details.In this example an X-XDV header was set so the backend server may choose to
serve different different CSS resources.Including external contentAs an event based server, it is not practical to adddocument()support to
the nginx XSLT module for in-transform inclusion. Instead, external content is
included through SSI in a sub-request. The SSI sub-request includes a query
string parameter to indicate which parts of the resultant document to include,
called;filter_xpath- see above for a full example. The configuration
below uses this parameter to apply a filter:worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include mime.types;
    gzip on;
    server {
        listen 80;
        server_name localhost;
        root html;

        # Decide if we need to filter
        if ($args ~ "^(.*);filter_xpath=(.*)$") {
            set $newargs $1;
            set $filter_xpath $2;
            # rewrite args to avoid looping
            rewrite    ^(.*)$    /_include$1?$newargs?;
        }

        location @include500 { return 500; }
        location @include404 { return 404; }

        location ^~ /_include {
            # Restrict _include (but not ?;filter_xpath=) to subrequests
            internal;
            error_page 404 = @include404;
            # Cache page fragments in Varnish for 1h when using ESI mode
            expires 1h;
            # Proxy
            rewrite    ^/_include(.*)$    $1    break;
            proxy_pass http://127.0.0.1:80;
            # Protect against infinite loops
            proxy_set_header X-Loop 1$http_X_Loop; # unary count
            proxy_set_header Accept-Encoding "";
            error_page 500 = @include500;
            if ($http_X_Loop ~ "11111") {
                return 500;
            }
            # Filter by xpath
            xslt_stylesheet filter.xsl
                xpath=$filter_xpath
                ;
            xslt_html_parser on;
            xslt_types text/html;
        }

        location / {
            xslt_stylesheet theme.xsl;
            xslt_html_parser on;
            xslt_types text/html;
            ssi on; # Not required in ESI mode
        }
    }
}In this example the sub-request is set to loop back on itself, so the include
is taken from a themed page.filter.xsl(in the lib/xdv directory) andtheme.xslshould both be placed in the same directory asnginx.conf.An example buildout is available innginx.cfgin this package.VarnishTo enable ESI in Varnish simply add the following to your VCL file:sub vcl_fetch {
    if (obj.http.Content-Type ~ "text/html") {
        esi;
    }
}An example buildout is available invarnish.cfg.ApacheXDV currently requires a version of mod_transform with html parsing support
and a disabled mod_depends. The latest patched versions may be downloaded from
thehtml-xslt project page.As well as the libxml2 and libxslt development packages, you will require
libapreq2 and the Apache development pacakges:$ sudo apt-get install libxslt1-dev libapache2-mod-apreq2 libapreq2-dev \
> apache2-threaded-devInstall mod_depends then mod_transform using the standard procedure:$ ./configure
$ make
$ sudo make installAn example virtual host configuration is shown below:NameVirtualHost *
LoadModule depends_module /usr/lib/apache2/modules/mod_depends.so
LoadModule transform_module /usr/lib/apache2/modules/mod_transform.so
<VirtualHost *>

    FilterDeclare THEME
    FilterProvider THEME XSLT resp=Content-Type $text/html

    TransformOptions +ApacheFS +HTML
    TransformSet /theme.xsl
    TransformCache /theme.xsl /etc/apache2/theme.xsl

    <LocationMatch "/">
        FilterChain THEME
    </LocationMatch>

</VirtualHost>The +ApacheFS directive enables XSLTdocument()inclusion.Unfortunately it is not possible to theme error responses (such as a 404 Not
Found page) with Apache as these do not pass through the filter chain.Changelog0.3 - 2010-05-29Added access control defaults, xdv.utils.AC_READ_NET, xdv.utils.AC_READ_FILE0.3rc2 - 2010-05-25Note: the current lxml Windows binaries are unable to load files over the
network.Fixed bug resolving the rules files while use a network theme.
[elro]0.3rc1 - 2010-05-23Nested <rules> are now allowed, so you can simply:``<xi:include href="standard-rules.xml" />``[elro]XInclude processing is now enabled by default
[elro]XSL directives inlined in the rules file are now supported (e.g.
<xsl:strip-space elements=”*” />). With the inline XSL support, there should
now be no need for extra.xsl.
[elro]libxml2 quotes CR characters on output, causing Firefox to insert extra
blank lines in<pre>blocks. As HTTP specified CRLF line endings for
form this was a problem for us. This is now caught by the compiled XSL.
[elro]Support for including complete fragment documents with SSI/ESI.
[elro]A bug on namespace upgrade is fixed, but you should update your namespace tohttp://namespaces.plone.org/xdvanyway.
[elro]First release candidate.
[elro]