跳转到主要内容

XDV使用纯XSLT引擎实现Deliverance子集。使用XDV,您可以一步“编译”您的主题和规则集,然后在每个请求后使用超快/简单的转换。或者,在开发期间编译您的主题,将其检查到Subversion,并在部署期间不接触XDV。

项目描述

简介

XDV是使用纯XSLT实现Deliverance概念的一种方法。简而言之,它是一种将包含在静态HTML网页(通常与相关的CSS、JavaScript和图像资源相关)中的样式/主题应用于使用任何服务器端技术创建的动态网站的方法。

考虑这样一个场景:你有一个动态网站,并希望应用一个由网页设计师制作的主题。网页设计师不熟悉动态网站背后的技术,因此提供了一个“静态HTML”版本的网站。这个版本包含一个带有更多或更少语义标记的HTML文件、一个或多个样式表,以及一些其他资源,如图片或JavaScript文件。

使用XDV,你可以将此主题应用于你的动态网站,具体方法如下

  1. 确定主题文件中需要用动态元素替换的占位符。理想情况下,这些应该很容易识别,例如使用唯一的HTML id 属性。

  2. 确定动态网站中相应的标记。然后使用XDV的规则语法编写一个“替换”或“复制”规则,用动态内容替换主题的静态占位符。

  3. 确定动态网站中应完整复制到主题中的标记。CSS和JavaScript链接在 <head /> 中通常这样处理。编写一个XDV的“追加”或“前置”规则来复制这些元素。

  4. 确定主题和/或动态网站中多余的元素。编写一个XDV的“删除”规则来移除这些元素。

规则文件使用简单的XML语法编写。可以使用CSS3或XPath选择器识别主题和“内容”(动态网站)中的元素。

一旦你有了主题HTML文件和规则XML文件,就可以使用XDV编译器将它们编译成一个单一的XSLT文件。然后你可以与应用程序一起部署这个XSLT文件。一个XSLT处理器(如Apache中的mod_transform)将随后将你的网站的动态内容转换为最终用户看到的主题内容。这个转换在每个请求时即时发生。

请注意

  • 你不必编写,甚至不必阅读任何XSLT代码(除非你想)。

  • 为每个请求发生的XSLT转换非常快。

  • 静态主题资源(如图片、样式表或JavaScript文件)可以从静态Web服务器上提供,这通常比从动态应用程序提供要快得多。

  • 你可以不修改原始的主题HTML文件,这使得它更容易在其他场景中重用。例如,你可以通过使用一个单独的主题文件和单独的规则文件将两个不相关的应用程序连接在一起。这将产生两个编译后的XSLT文件。你可以使用位置匹配规则或类似的技术来选择为特定请求调用哪一个。

以下我们将说明如何为部署设置XDV。

安装

要安装XDV,你应该安装 xdv egg。你可以使用 easy_installpipzc.buildout 来这样做。例如,使用 easy_install(理想情况下在 virtualenv 中)

$ easy_install -U xdv

如果你使用 zc.buildout,你可以使用以下 buildout.cfg 作为起点。这将确保控制台脚本被安装,这在需要手动执行XDV编译器时很重要

[buildout]
parts =
    xdv

[xdv]
recipe = zc.recipe.egg
eggs = xdv

注意 lxmlxdv 的依赖项,因此你可能需要安装libxml2和libxslt开发包,以便它能够构建。在Debian/Ubuntu上,你可以运行

$ sudo apt-get install libxslt1-dev

在某些操作系统上,特别是Mac OS X,安装一个“好的” lxml egg可能会有问题,因为 lxml 使用的 libxml2libxslt 库的操作系统版本不匹配。为了解决这个问题,你可以使用以下buildout配方编译一个静态的 lxml egg

[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 = xdv

安装完成后,您应该在 bin 目录中找到 xdvcompilerxdvrun

规则文件语法

规则文件,通常称为 rules.xml,位于一个名为 <rules /> 的标签中。

<?xml version="1.0" encoding="UTF-8"?>
<rules xmlns="http://namespaces.plone.org/xdv"
       xmlns:css="http://namespaces.plone.org/xdv+css">

       ...

</rules>

这里定义了两个命名空间:默认命名空间用于规则和 XPath 选择器。CSS 命名空间用于 CSS3 选择器。这些在功能上是等效的。事实上,在编译器的预处理步骤中,CSS 选择器会被等价的 XPath 选择器替换。因此,它们对性能没有影响。

XDV 支持复杂的 CSS3 和 XPath 选择器,包括像 nth-child 伪选择器这样的东西。如果您对 XPath 和/或 CSS3 不是很熟悉,建议您查阅良好的参考资料。

以下元素可以在 <rules /> 元素内部使用

<replace />

用于完全用内容中的元素替换主题中的元素。例如

<replace theme="/html/head/title" content="/html/head/title"/>

使用 CSS 选择器的等效写法将是

<replace css:theme="title" css:content="title"/>

两种方式的结果都是将主题中的 <title /> 元素替换为(动态)内容中的 <title /> 元素。

<copy />

用于用主题中的标签替换占位符标签的内容。例如

<copy css:theme="#main" css:content="#portal-content > *" />

这将用主题中 id 为 main 的元素的所有子元素替换内容中 id 为 portal-content 的元素中的任何占位符内容。使用 <copy /> 而不是 <replace /> 的通常原因是因为主题中目标元素(在本例中是 id 为 main 的元素)附有 CSS 样式或其他行为。

<append /><prepend />

用于将内容中的元素复制到主题中的元素,同时保留现有内容。 <append /> 将匹配的内容直接放在主题的关闭标签之前;<prepend /> 将其直接放在打开标签之后。例如

<append theme="/html/head" content="/html/head/link" />

这将把内容头部中的所有 <link /> 元素复制到主题中。

作为特殊情况,您可以使用 <prepend /> 将内容元素的个别 属性 复制到主题中的元素

<prepend theme="/html/body" content="/html/body/@class" />

这将把内容中 <body /> 元素的 class 属性复制到主题中(如果存在同名属性,则替换它)。

<before /><after />

这些与 <append /><prepend /> 相当同,但将匹配的内容放在匹配的主题元素之前或之后,而不是直接放在其中。例如

<before css:theme=”#content” css:content=”#info-box” />

这将把内容中 id 为 info-box 的元素立即放在主题中 id 为 content 的元素之前。如果我们想将框放在内容下方,我们可以这样做

<after css:theme="#content" css:content="#info-box" />

<drop />

用于从主题或内容中删除元素。这是唯一接受 themecontent 属性(或它们的 css: 等效属性)的元素,但不接受两者

<drop css:content="#portal-content .about-box" />
<copy css:theme="#content" css:content="#portal-content > *" />

这将把主题中 id 为 portal-content 的元素的所有子元素复制到主题中 id 为 content 的元素中,但首先删除内容元素内部任何具有 class about-box 的元素。同样

<drop theme="/html/head/base" />

将删除主题头部的 <base /> 标签。

规则执行顺序

在大多数情况下,您不必过于关注XDV编译器的内部工作原理。然而,了解规则应用顺序有时可能很有用。

  1. <before /> 规则始终首先执行。

  2. <drop /> 规则接着执行。

  3. <replace /> 规则接着执行,前提是没有对同一主题节点应用 <drop /> 规则。

  4. <prepend /><copy /><append /> 规则接着执行,前提是没有对同一主题节点应用 <replace /> 规则。

  5. <after /> 规则最后执行。

如果主题或内容不匹配的行为

如果一个规则不符合主题(无论是否与内容匹配),它将被静默忽略。

如果一个 <replace /> 规则与主题匹配但与内容不匹配,匹配的元素将在主题中被删除

<replace css:theme="#header" content="#header-element" />

在这里,如果带有 id header-element 的元素在内容中未找到,则主题中的带有 id header 的占位符将被移除。

类似地,如果未找到匹配的内容,则使用 <copy /> 规则匹配的主题节点的内容将被删除。另一种思考方式是,如果没有匹配的内容节点,XDV在复制或替换时将使用空节点集。

如果您希望占位符在内容节点缺失的情况下保持位置,可以将此作为一个条件规则

<replace css:theme="#header" content="#header-element" if-content="" />

下面将详细介绍有关条件规则的更多详细信息。

高级用法

上述简单规则应该适用于大多数用例。但是,如果您需要,还有更多高级工具可供您使用。

条件规则

有时,仅当给定的元素出现在或未出现在标记中时,才应用规则很有用。可以与任何规则一起使用 if-content 属性使其成为条件。

if-content 应设置为一个 XPath 表达式。您还可以使用 css:if-content 与一个 CSS3 表达式。如果表达式匹配内容中的节点,则应用该规则

<copy css:theme="#portlets" css:content=".portlet"/>
<drop css:theme="#portlet-wrapper" if-content="not(//*[@class='portlet'])"/>

这将复制所有具有 class portlet 的元素到 portlets 元素中。如果没有匹配的元素在内容中,我们将丢弃 portlet-wrapper 元素,这可能是多余的。

以下是一个使用 CSS 选择器的示例

<copy css:theme="#header" css:content="#header-box > *"
      css:if-content="#personal-bar"/>

这将复制内容中具有 id header-box 的元素的子元素到主题中具有 id header 的元素中,前提是内容中也有一个具有 id personal-bar 的元素。

在上文中,我们还看到了一个特殊的空 if-content 的情况(这也适用于空的 css:if-content)。这是一个快捷方式,表示“使用 contentcss:content` 属性中的表达式作为条件”。因此,以下两个规则是等效的

<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-content 表达式,它们将作为一个 if..else if…else 块组合

<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()" />

这些规则都试图填充正文中的 <h1 /> 文本。第一条规则寻找相似的 <h1 /> 标签并使用其文本。如果这不匹配,第二条规则寻找任何具有 id first-heading<h1 />,并使用其文本。如果这两个都不匹配,最后一条规则将作为后备使用(因为它没有 if-content),取内容文档头部 <title /> 标签的内容。

包含外部内容

通常,任何规则的 content 属性会选择来自底层动态 Web 服务器的响应节点。然而,可以使用任何规则(除了 <drop />)上的 href 属性包含来自不同 URL 的内容。例如

<append css:theme="#left-column" css:content="#portlet" href="/extra.html"/>

这将解析 URL /extra.html,寻找 id 为 portlet 的元素,然后将其附加到主题中 id 为 left-column 的元素。

包含可以通过以下三种方式之一实现

  • 使用 XSLT document() 函数。这是默认操作,但可以通过在规则元素中添加一个属性 method="document" 来显式指定。是否能够解析 URL 取决于编译的 XSLT 是如何和在哪里执行的

    <append css:theme="#left-column" css:content="#portlet"
            href="/extra.html" method="document" />
  • 通过服务器端包含指令。可以通过将 method 属性设置为 ssi 来指定

    <append css:theme="#left-column" css:content="#portlet"
            href="/extra.html" method="ssi"/>

    输出将类似于以下内容

    <!--# include wait="yes" virtual="/extra.html?;filter_xpath=//*[@id%20=%20'portlet']" -->

    这个 SSI 指令需要由 Apache 或 nginx 等前端 Web 服务器处理。此外,请注意 ;filter_xpath 查询字符串参数。由于我们是在 SSI 处理期间(即在编译的 XDV XSLT 转换执行之后)延迟解析引用的文档,我们需要请求 SSI 处理器过滤掉我们不感兴趣的元素。这需要特定的配置。以下是一个 nginx 的示例。

    对于简单的整个文档的 SSI 包含,您可能从规则中省略 content 选择器

    <append css:theme="#left-column" href="/extra.html" method="ssi"/>

    然后输出将渲染如下

    <!--# include wait="yes" virtual="/extra.html" -->
  • 通过边侧包含指令。可以通过将 method 属性设置为 esi 来指定

    <append css:theme="#left-column" css:content="#portlet"
            href="/extra.html" method="esi"/>

    输出类似于 SSI 模式

    <esi:include src="/extra.html?;filter_xpath=//*[@id%20=%20'portlet']"></esi:include>

    同样,指令需要由 Varnish 等前端服务器处理。可能的情况是,一个了解 ESI 的缓存服务器不会支持任意的 XPath 过滤。如果引用的文件由动态 Web 服务器提供服务,它可能能够检查 ;filter_xpath 参数并返回一个定制响应。否则,如果在一个可以通知缓存服务器和底层 Web 服务器的服务器之间放置一个可以通知此信息的服务器,该服务器可以执行必要的过滤。

    对于简单的整个文档的 ESI 包含,您可能从规则中省略 content 选择器

    <append css:theme="#left-column" href="/extra.html" method="esi"/>

    然后输出将渲染如下

    <esi:include src="/extra.html"></esi:include>

动态修改主题

有时,主题几乎是完美的,但无法修改,例如因为它来自一个您无法访问的远程位置,或者因为它与其他应用程序共享。

XDV 允许您通过规则文件中的“内联”标记修改主题。您可以将此视为一个在规则文件中显式声明匹配 content 的规则,而不是从正在样式化的响应中提取。

例如

<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>

注意我们将规则放置在一个显式的 xdv 命名空间中,这样我们就可以在“内联”HTML 中写入没有命名空间前缀的内容。

在上面的示例中,<append /> 规则会将 <style /> 属性及其内容复制到主题的 <head /> 中。可以构建类似的规则来处理 <copy /><replace /><prepend /><before /><after />

甚至可以通过这种方式在编译后的主题中插入 XSLT 指令。如上所述,已经声明了 xsl 命名空间,我们可以这样做

<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>

注意,CSS 表达式会被转换为“无位置”的 XPath 表达式,因此 css:select="table#details" > tr" 转换为 select="//table[@id='details']/tr"。这意味着无法使用 css:select="td:first-child > *",因为你在这里需要一个相对选择器。当然,你可以在 select 属性中手动使用 XPath。

内联XSL指令

你可以在规则中提供内联 XSL 指令来调整最终输出,例如,要从输出文档中删除空格,请使用

<rules xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

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

</rules>

注意:这可能会影响浏览器中的页面渲染。

要使用严格的 doctype

<xsl:output
    doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
    doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"/>

XInclude

你可能希望在多个主题之间重用规则文件中的元素。如果你在同一个网站上使用同一主题的不同变体来设计不同的页面,这将特别有用。

可以使用 XInclude 协议包含规则文件。

包含使用标准的 XInclude 语法。例如

<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>

编译

一旦你编写了你的规则文件,你需要将其编译为 XSLT 以进行部署。在某些情况下,你可能有一个应用程序服务器可以动态完成此操作,例如,如果你正在使用 Plone 的 collective.xdv 软件包。但是,要将部署到 Apache 或 nginx 等网络服务器,你将需要手动执行此步骤。

调用 XDV 编译器最简单的方法是通过与 xdv egg 一起安装的 xdvcompiler 命令行脚本。要查看其帮助输出,请执行

$ bin/xdvcompiler --help

使用 rules.xml 操作 theme.html

$ bin/xdvcompiler rules.xml theme.html

这将打印编译的 XSLT 文件到标准输出。你可以将其保存到文件中,如下所示

$ bin/xdvcompiler -o theme.xsl rules.xml theme.html

以下命令行选项是可用的

  • 使用 -p 来美化输出,以改善可读性。但是,这可能会改变浏览器中的渲染,因为浏览器对某些类型的空白很敏感。

  • 使用 -a 设置一个绝对前缀 - 详见下文。

  • 使用 -i 设置默认的外部文件包含模式为 documentssiesi 之一。

  • 使用 --trace 在编译步骤中输出跟踪日志。这对于调试规则很有帮助。

检查 --help 选项的输出以获取更多详细信息。

绝对前缀

编译器可以传递一个“绝对前缀”。这是一个字符串,它将在将主题传递给编译器之前添加到主题 HTML 文件中引用的任何 相对 URL(图片、链接或样式表)之前。这允许主题被编写成可以在文件系统上独立打开和查看,即使在其运行时其静态资源将从其他位置提供。

例如,假设主题是用相对URL编写的,用于图像和外部资源,如<img src="images/foo.jpg" />。当将编译后的主题应用于实际网站时,除了images文件夹的同级之外,其他URL可能都无法正常工作。

假设主题的静态资源由一个简单的Web服务器提供,并在目录/static下可用。在这种情况下,我们可以设置一个绝对前缀/static。这将修改编译主题中的<img />标签,使其成为一个适用于任何URL的绝对路径:<img src="/static/images/foo.jpg" />

测试编译后的主题

为了测试编译后的主题,您可以将它应用于代表内容的静态文件。最简单的方法是通过xdvrun脚本

$ bin/xdvrun theme.xsl content.html

这将输出到标准输出。您也可以使用以下命令将其保存到文件

$ bin/xdvrun -o output.html theme.xsl content.html

为了测试,您也可以使用xdvrun-r(规则)和-t(主题)参数一次编译并运行主题

$ bin/xdvrun -o output.html -r rules.xml -t theme.html content.html

要查看此命令的内置帮助,请运行

$ bin/xdvrun --help

在Python代码中编译主题

您可以使用以下辅助函数从Python代码中运行XDV编译器

>>> from xdv.compiler import compile_theme

此方法接受以下参数

  • rules是规则文件,可以是文件名或包含文件内容的字符串。

  • theme是主题文件,可以是文件名或包含文件内容的字符串。

  • extra是一个可选的XSLT文件,带有XDV扩展,以URI的形式给出(已弃用,请在规则中使用内联xsl代替)。

  • css可以设置为False以禁用CSS语法支持(提供适度的速度提升)。

  • xinclude可以设置为False以启用XInclude支持(以适度的速度成本)。如果启用,XInclude语法可以用于将规则文件拆分为多个可重用的片段。

  • absolute_prefix可以设置为字符串,用作相对URL的“绝对前缀” - 见上文。

  • update可以设置为False以禁用对旧Deliverance 0.2命名空间的自动更新支持(以适度的速度提升)。

  • trace可以设置为True以启用编译器跟踪信息。

  • includemode可以设置为‘document’、‘esi’或‘ssi’以更改处理包含的方式。

  • parser可以设置为lxml解析器实例;默认是HTMLParser。

  • compiler_parser可以设置为lxml解析器实例;默认是XMLParser。

  • rules_parser可以设置为lxml解析器实例;默认是XMLParse。

如果需要,可以使用解析器参数添加外部内容的自定义解析器。有关详细信息,请参阅lxml文档。

compile_theme()返回一个以lxml的ElementTree格式的XSLT文档。要设置表示主题和规则的转换,您可以这样做

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)

现在您可以使用这个转换

content = etree.parse(some_content)
transformed = transform(content)

output = etree.tostring(transformed)

有关更多详细信息,请参阅lxml文档。

部署

在可以使用之前,部署的主题需要部署到代理Web服务器,该服务器可以将XSLT应用于来自另一个Web应用的响应。

理论上,任何XSLT处理器都可以。然而,在实践中,大多数网站并不生成100%格式良好的XML(即,它们不符合XHTML“严格”文档类型)。因此,通常需要使用一个可以解析内容的XSLT处理器,使用一个更宽松的解析器并具有一些HTML知识。libxml2是Linux和类似操作系统上最受欢迎的XML处理库,其中包含这样一个解析器。

Plone

如果您正在使用Plone,使用XDV的最简单方法是使用collective.xdv插件。它提供了一个控制面板来配置XDV规则文件、主题和其他选项,并在Plone渲染最终页面之后执行转换链以应用XDV转换。

即使您打算将编译后的主题部署到另一个Web服务器,collective.xdv也是一个有用的开发工具:只要Zope处于“开发模式”,它就会即时重新编译主题,让您可以即时更改主题和规则。它还提供了一些工具来打包您的主题并将其部署到不同的网站。

WSGI

如果您使用WSGI堆栈,可以使用dv.xdvserver中间件来应用XDV主题。它支持所有核心XDV选项,并且可以配置为即时重新编译主题(对开发很有用),或者只编译一次(对部署很有用)。

您还可以与Paste proxy 中间件一起使用,为任何网站创建一个独立的XDV代理。有关详细信息,请参阅dv.xdvserver文档。

nginx

要将XDV主题部署到nginx Web服务器,您需要编译nginx,使用一个特殊的XSLT模块版本,该模块可以(可选)使用libxml2的HTML解析器。

在未来,启用HTML模式解析的必要补丁有望成为标准nginx分发的部分。同时,它们被维护在html-xslt项目中。

使用正确修补的nginx,您可以像这样配置它以支持XSLT

$ ./configure --with-http_xslt_module

如果您使用zc.buildout并希望构建nginx,可以从以下示例开始

[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_module

如果libxml2或libxslt安装在不标准的位置,您可能需要提供--with-libxml2=<path>--with-libxslt=<path>选项。这要求您在运行nginx时设置适当的LD_LIBRARY_PATH(Linux / BSD)或DYLD_LIBRARY_PATH(Mac OS X)环境变量。

要为主题静态站点,请在nginx配置中启用XSLT转换,如下所示

location / {
    xslt_stylesheet /path/to/compiled-theme.xsl;
    xslt_html_parser on;
    xslt_types text/html;
}

nginx还可以配置为转换代理服务器

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 "";
}

有时需要删除Accept-Encoding头部,以防止后端服务器压缩响应(并防止转换)。响应可能在nginx中通过设置gzip on;来压缩 - 有关详细信息,请参阅gzip模块文档

在此示例中设置了一个X-XDV头部,以便后端服务器可以选择提供不同的CSS资源。

包含外部内容

作为基于事件的服务器,向nginx XSLT模块添加document()支持以进行转换内包含是不切实际的。相反,外部内容通过子请求中的SSI包含。SSI子请求包括一个查询字符串参数,指示要包含的结果文档的部分,称为;filter_xpath - 如上所示为完整示例。下面的配置使用此参数应用过滤器

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
        }
    }
}

在这个示例中,子请求被设置为自我循环,因此包含是从主题页面中提取的。请将 filter.xsl(位于 lib/xdv 目录)和 theme.xsl 都放置在与 nginx.conf 相同的目录中。

本包中的 nginx.cfg 包含一个示例构建文件。

Varnish

要启用 Varnish 中的 ESI,只需将以下内容添加到您的 VCL 文件中

sub vcl_fetch {
    if (obj.http.Content-Type ~ "text/html") {
        esi;
    }
}

varnish.cfg 中提供了一个示例构建文件。

Apache

XDV 当前需要具有 HTML 解析支持的 mod_transform 版本和禁用的 mod_depends。最新的修补版本可以从 html-xslt 项目页面 下载。

除了 libxml2 和 libxslt 开发包外,您还需要 libapreq2 和 Apache 开发包。

$ sudo apt-get install libxslt1-dev libapache2-mod-apreq2 libapreq2-dev \
> apache2-threaded-dev

使用标准程序安装 mod_depends,然后安装 mod_transform。

$ ./configure
$ make
$ sudo make install

以下是一个示例虚拟主机配置。

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>

+ApacheFS 指令启用 XSLT document() 包含。

遗憾的是,无法使用 Apache 主题错误响应(例如 404 未找到页面),因为这些不会通过过滤器链。

变更日志

0.3 - 2010-05-29

  • 添加了默认访问控制,xdv.utils.AC_READ_NET,xdv.utils.AC_READ_FILE

0.3rc2 - 2010-05-25

注意:当前的 lxml Windows 二进制文件无法加载网络上的文件。

  • 修复了在使用网络主题时解析规则文件的错误。[elro]

0.3rc1 - 2010-05-23

  • 现在允许嵌套 <rules>,因此您可以简单地

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

    [elro]

  • 默认启用 XInclude 处理。[elro]

  • 现在支持在规则文件中内联 XSL 指令(例如,<xsl:strip-space elements="*" />)。有了内联 XSL 支持,现在应该不需要 extra.xsl。[elro]

  • libxml2 在输出时引用 CR 字符,导致 Firefox 在 <pre> 块中插入额外的空白行。由于 HTTP 为表单指定了 CRLF 行结束符,这对我们来说是个问题。现在,编译的 XSL 可以捕获这个问题。[elro]

  • 支持使用 SSI/ESI 包含完整的片段文档。[elro]

  • 已修复命名空间升级上的错误,但您仍然应该将命名空间更新到 http://namespaces.plone.org/xdv。[elro]

  • 第一个候选版本。[elro]

项目详情


下载文件

下载您平台上的文件。如果您不确定选择哪个,请了解有关 安装包 的更多信息。

源代码分发

xdv-0.3.tar.gz (169.3 kB 查看哈希值

上传时间 源代码