2015-04-29 21 views
2

我一直在想如何最好地模塊化我的XSLT樣式表以方便重用。我碰到了使用< xsl:apply-imports />作爲將文檔特定屬性引入標準標籤轉換的方法的想法。這是而不是按我期望的方式工作,我甚至無法開始深究這裏發生的事情。這裏是樣式表的簡化版本:意外的<xsl:apply-imports />行爲

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

導入的樣式表:

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

下面是XML輸入文件:

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

$ xalan的-o out.xml測試.xml main.xsl

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:apply-imports />的模板匹配元素的每個子元素!我包含了導入的樣式表,以說明我正在嘗試做什麼。如果我註釋掉此導入:

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

的重複行爲是一樣的:

<?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>Spongebob Squarepants, <fo:inline font-style="italic">ChairChair</fo:inline>Spongebob Squarepants, <fo:inline font-style="italic">ChairChair</fo:inline> 
</fo:table-cell> 
<fo:table-cell>Spongebob Squarepants, <fo:inline font-style="italic">ChairChair</fo:inline>Spongebob Squarepants, <fo:inline font-style="italic">ChairChair</fo:inline> 
</fo:table-cell> 
</fo:table-row> 
    <fo:table-row> 
... 
... 

SANS我試圖從導入的樣式表添加屬性;即< xsl:apply-imports />處理指令的存在導致輸出元素加倍。另外請注意,這不僅僅是一個xalan問題 - 同樣的事情發生在Windows 7上的MSXML上。

有什麼想法?我指望這個工作,所以我現在拉着我的頭髮試圖找出如何解決這個問題,因此它的工作原理。

順便說一句,我如何使用< xsl:apply-imports />的假設是基於Michael Kay書中的xsl:import部分給出的示例。如果有人知道解釋我上面看到的行爲的參考資料,請分享。

回答

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> 

正如你可以看到,我已刪除了2個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程序員參考由邁克爾·凱,頁238

+0

感謝,馬蒂亞斯解釋 - 那我的回答題。在你的例子中,你還需要從 - 注意斜體文本仍然加倍;例如ChairChair。不幸的是,這並不能解決我的問題,因爲我希望主要樣式表(實際上是爲簡化問題的設計 - 實際上,在中間樣式表中)我希望能夠完全未經編輯的使用。如果我不得不編輯這個樣式表,我不妨將其轉換成模板。 – pgoetz

+0

與此同時,我想我已經想到了另一種方法:在包含樣式表中定義的每個元素上調用泛型屬性集,其中可能包含或不包含任何內容。我會多思考這個問題,然後發表一個榜樣,讓下一個有關此問題的人士受益。再次感謝!因爲實際的樣式表非常長且複雜,我以爲我昨天試圖去調試它。我花了幾個小時才發現對我的痛苦負責。 – pgoetz

+0

@pgoetz你是對的,編輯我的答案以刪除'apply-imports'。不會將屬性集分配給元素也不需要編輯主樣式表? –