意外的<xsl:apply-imports>行为

时间:2015-04-29 12:31:27

标签: xml xslt xslt-1.0 xsl-fo

我一直在努力弄清楚如何最好地模块化我的XSLT样式表以便于重复使用。我想到了使用&lt; xsl:apply-imports /&gt;的想法。作为向标准标记转换引入特定于文档的属性的一种方式。这是以我预期的方式工作,我甚至无法理解这里发生的事情。以下是样式表的简化版本:

Provider<HTTPRequest> mockHttpRequestProvider = mock(Provider.class);
when(mockHttpReqestProvider.get()).thenReturn(yourMockHTTPRequestObject);
// Set this mock provider to the ModelClass instance. (You may have to use reflection)

导入的样式表:

<!-- main.xsl -->
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet  version="1.0"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:fo="http://www.w3.org/1999/XSL/Format">

<xsl:import href="html-customizations.xsl"/>

<xsl:output method="xml"
   indent="yes"
   omit-xml-declaration="no"/>

<xsl:template match="para">
  <fo:block>
      <xsl:attribute name="space-after">1em</xsl:attribute>
      <xsl:apply-templates/>
  </fo:block>
</xsl:template>

<!-- =============== -->
<!-- Inline Elements -->
<!-- =============== -->

<xsl:template match="i">
  <fo:inline font-style="italic">
    <xsl:apply-imports/>
    <xsl:apply-templates/>
  </fo:inline>
</xsl:template>

<!-- ================ -->
<!--      Tables      -->
<!-- ================ -->

<xsl:template match="table">
  <fo:table>
    <xsl:apply-imports/>
    <xsl:apply-templates/>
  </fo:table>
</xsl:template>

<xsl:template  match="tr">
  <fo:table-row>
    <xsl:apply-imports/>
    <xsl:apply-templates/>
  </fo:table-row>
</xsl:template>

<xsl:template match="td | th">
  <fo:table-cell>
    <xsl:apply-imports/>
    <xsl:apply-templates/>
  </fo:table-cell>
</xsl:template>
</xsl:stylesheet>

这是XML输入文件:

<!-- html-customizations.xsl -->
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet  version="1.0"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:fo="http://www.w3.org/1999/XSL/Format">

<xsl:template  match="td | th">
  <xsl:attribute name="hyphenate">true</xsl:attribute>
</xsl:template>

</xsl:stylesheet>

$     xalan -o out.xml test.xml main.xsl

<!-- test.xml -->
<para>
  <table>
    <tr><td>Spongebob Squarepants, <i>Chair</i></td></tr>
    <tr><td>Patrick Starfish, <i>Vice Cchair</i></td></tr>
    <tr><td>Squidword, <i>Secretary</i></td></tr>
  </table>
</para>

如您所见,元素的每个子元素都与包含&lt; xsl:apply-imports /&gt;的模板匹配。重复!我包含了导入的样式表,以说明我正在尝试做什么。如果我注释掉这个导入:

out.xml:
<?xml version="1.0" encoding="UTF-8"?>
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" space-after="1em">
  <fo:table>
    <fo:table-row>
<fo:table-cell hyphenate="true">Spongebob Squarepants, <fo:inline font-style="italic">ChairChair</fo:inline>
</fo:table-cell>
<fo:table-cell hyphenate="true">Spongebob Squarepants, <fo:inline font-style="italic">ChairChair</fo:inline>
</fo:table-cell>
</fo:table-row>
    <fo:table-row>
<fo:table-cell hyphenate="true">Patrick Starfish, <fo:inline font-style="italic">Vice CchairVice Cchair</fo:inline>
</fo:table-cell>
<fo:table-cell hyphenate="true">Patrick Starfish, <fo:inline font-style="italic">Vice CchairVice Cchair</fo:inline>
</fo:table-cell>
</fo:table-row>
    <fo:table-row>
<fo:table-cell hyphenate="true">Squidword, <fo:inline font-style="italic">SecretarySecretary</fo:inline>
</fo:table-cell>
<fo:table-cell hyphenate="true">Squidword, <fo:inline font-style="italic">SecretarySecretary</fo:inline>
</fo:table-cell>
</fo:table-row>

    <fo:table-row>
<fo:table-cell hyphenate="true">Spongebob Squarepants, <fo:inline font-style="italic">ChairChair</fo:inline>
...
...

重复行为是相同的:

<!--
<xsl:import href="html-customizations.xsl"/>
-->

没有尝试从导入的样式表添加的属性;即只是&lt; xsl:apply-imports /&gt;的存在处理指令使输出元素加倍。另请注意,这不仅仅是 xalan 问题 - 在Windows 7上的MSXML上也会发生同样的事情。

有什么想法?我指望这个工作,所以我现在正在试着弄清楚如何解决这个问题,以便它有效。

BTW,我对如何&lt; xsl:apply-imports /&gt;的假设?可以使用的是基于Michael Kay的书的 xsl:import 部分给出的示例。如果有人知道解释我上面看到的行为的参考,请分享。

1 个答案:

答案 0 :(得分:4)

我同意apply-imports的行为很难理解。问题是apply-imports 总是找到与当前节点匹配的模板,即使用户没有定义它也是如此。在这种情况下,默认模板适用。

以下样式表有效:

XSLT样式表

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet  version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:fo="http://www.w3.org/1999/XSL/Format">

    <xsl:import href="html-customizations.xsl"/>

    <xsl:output method="xml"
        indent="yes"
        omit-xml-declaration="no"/>

    <xsl:template match="para">
        <fo:block>
            <xsl:attribute name="space-after">1em</xsl:attribute>
            <xsl:apply-templates/>
        </fo:block>
    </xsl:template>

    <!-- =============== -->
    <!-- Inline Elements -->
    <!-- =============== -->

    <xsl:template match="i">
        <fo:inline font-style="italic">
            <xsl:apply-templates/>
        </fo:inline>
    </xsl:template>

    <!-- ================ -->
    <!--      Tables      -->
    <!-- ================ -->

    <xsl:template match="table">
        <fo:table>

            <xsl:apply-templates/>
        </fo:table>
    </xsl:template>

    <xsl:template  match="tr">
        <fo:table-row>

            <xsl:apply-templates/>
        </fo:table-row>
    </xsl:template>

    <xsl:template match="td | th">
        <fo:table-cell>
            <xsl:apply-imports/>
            <xsl:apply-templates/>
        </fo:table-cell>
    </xsl:template>
</xsl:stylesheet>

正如您所看到的,我删除了两个apply-imports元素,只留下template/@match='td | th'内的元素。然后,输出将是

XML输出

<?xml version="1.0" encoding="UTF-8"?>
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" space-after="1em">
    <fo:table>
        <fo:table-row>
         <fo:table-cell hyphenate="true">Spongebob Squarepants, <fo:inline font-style="italic">ChairChair</fo:inline>
         </fo:table-cell>
      </fo:table-row>
        <fo:table-row>
         <fo:table-cell hyphenate="true">Patrick Starfish, <fo:inline font-style="italic">Vice CchairVice Cchair</fo:inline>
         </fo:table-cell>
      </fo:table-row>
        <fo:table-row>
         <fo:table-cell hyphenate="true">Squidword, <fo:inline font-style="italic">SecretarySecretary</fo:inline>
         </fo:table-cell>
      </fo:table-row>
    </fo:table>
</fo:block>

到底发生了什么?

apply-imports寻找

的模板
  • 匹配当前节点
  • 匹配当前模式
  • 位于导入的样式表

现在,关键的一点是:如果在导入的样式表中找不到这样的模板,则该指令将调用built-in templates。如果是tr

<xsl:template  match="tr">
  <fo:table-row>
    <xsl:apply-imports/>
    <xsl:apply-templates/>
  </fo:table-row>
</xsl:template>

元素节点的默认操作是遍历它并将模板应用于其内容,因此上面的代码段实际上转换为

<xsl:template  match="tr">
  <fo:table-row>
    <xsl:apply-templates/>
    <xsl:apply-templates/>
  </fo:table-row>
</xsl:template>

这就是输出包含重复项的原因。我现在假设您也理解为什么评论xsl:import没有帮助,否则我很乐意详细说明。

由于您还要求引用,所以 XSLT 2.0和XPath 2.0程序员参考中由Michael Kay解释,第238页。