xsl:next-matchについて紹介します.xs:next-matchは、複数のマッチングするテンプレートがあった場合に、最終的に選択されたテンプレート内から、次の優先順位でマッチングするテンプレートを階層的に呼び出せる機能です.
例えばDITA→XSL-FOでxsl:next-matchは次のように使うことができます.
<xsl:template match="*[contains(@class,' topic/ph ')]" priority="1">
<xsl:param name="prmAttNode" as="attribute()*" required="no" select="()"/>
<fo:inline>
<xsl:copy-of select="$prmAttNode"/>
<xsl:apply-templates/>
</fo:inline>
</xsl:template>
<xsl:param name="prmAttNode" as="attribute()*" required="no" select="()"/>
<fo:inline>
<xsl:copy-of select="$prmAttNode"/>
<xsl:apply-templates/>
</fo:inline>
</xsl:template>
<xsl:template match="*[contains(@class,' hi-d/b ')]" priority="2">
<xsl:next-match>
<xsl:with-param name="prmAttNode" select="$attB"/>
</xsl:next-match>
</xsl:template>
<xsl:template match="*[contains(@class,' hi-d/i ')]" priority="2">
<xsl:next-match>
<xsl:with-param name="prmAttNode" select="$attI"/>
</xsl:next-match>
</xsl:template>
<xsl:template match="*[contains(@class,' hi-d/u ')]" priority="2">
<xsl:next-match>
<xsl:with-param name="prmAttNode" select="$attU"/>
</xsl:next-match>
</xsl:template>
<xsl:template match="*[contains(@class,' hi-d/tt ')]" priority="2">
<xsl:next-match>
<xsl:with-param name="prmAttNode" select="$attTt"/>
</xsl:next-match>
</xsl:template>
<xsl:template match="*[contains(@class,' hi-d/sup ')]" priority="2">
<xsl:next-match>
<xsl:with-param name="prmAttNode" select="$attSup"/>
</xsl:next-match>
</xsl:template>
<xsl:template match="*[contains(@class,' hi-d/sub ')]" priority="2">
<xsl:next-match>
<xsl:with-param name="prmAttNode" select="$attSub"/>
</xsl:next-match>
</xsl:template>
<xsl:next-match>
<xsl:with-param name="prmAttNode" select="$attB"/>
</xsl:next-match>
</xsl:template>
<xsl:template match="*[contains(@class,' hi-d/i ')]" priority="2">
<xsl:next-match>
<xsl:with-param name="prmAttNode" select="$attI"/>
</xsl:next-match>
</xsl:template>
<xsl:template match="*[contains(@class,' hi-d/u ')]" priority="2">
<xsl:next-match>
<xsl:with-param name="prmAttNode" select="$attU"/>
</xsl:next-match>
</xsl:template>
<xsl:template match="*[contains(@class,' hi-d/tt ')]" priority="2">
<xsl:next-match>
<xsl:with-param name="prmAttNode" select="$attTt"/>
</xsl:next-match>
</xsl:template>
<xsl:template match="*[contains(@class,' hi-d/sup ')]" priority="2">
<xsl:next-match>
<xsl:with-param name="prmAttNode" select="$attSup"/>
</xsl:next-match>
</xsl:template>
<xsl:template match="*[contains(@class,' hi-d/sub ')]" priority="2">
<xsl:next-match>
<xsl:with-param name="prmAttNode" select="$attSub"/>
</xsl:next-match>
</xsl:template>
<xsl:variable name="attB" as="attribute()*">
<xsl:attribute name="font-weight" select="'bold'"/>
</xsl:variable>
<xsl:variable name="attI" as="attribute()*">
<xsl:attribute name="font-style" select="'italic'"/>
</xsl:variable>
<xsl:variable name="attU" as="attribute()*">
<xsl:attribute name="text-decoration" select="'underline'"/>
</xsl:variable>
<xsl:variable name="attTt" as="attribute()*">
<xsl:attribute name="font-family" select="'Courier New'"/>
<xsl:attribute name="font-size" select="'0.9em'"/>
</xsl:variable>
<xsl:variable name="attSup" as="attribute()*">
<xsl:attribute name="font-size" select="'0.8em'"/>
<xsl:attribute name="baseline-shift" select="'super'"/>
</xsl:variable>
<xsl:variable name="attSub" as="attribute()*">
<xsl:attribute name="font-size" select="'0.8em'"/>
<xsl:attribute name="baseline-shift" select="'sub'"/>
</xsl:variable>
<xsl:template match="p">
<fo:block>
<xsl:apply-templates/>
</fo:block>
</xsl:template>
<fo:block>
<xsl:apply-templates/>
</fo:block>
</xsl:template>
これに
<p>
<b>Bold</b>
<i>Italic</i>
<u>Underline</u>
<tt>Teletype</tt>
<sup>Superscript</sup>
<sub>Subscript</sub>
</p>
<b>Bold</b>
<i>Italic</i>
<u>Underline</u>
<tt>Teletype</tt>
<sup>Superscript</sup>
<sub>Subscript</sub>
</p>
のようなデータを入力すれば、
<fo:block>
<fo:inline font-weight="bold">Bold</fo:inline>
<fo:inline font-style="italic">Italic</fo:inline>
<fo:inline text-decoration="underline">Underline</fo:inline>
<fo:inline font-family="Courier New" font-size="0.9em">Teletype</fo:inline>
<fo:inline font-size="0.8em" baseline-shift="super">Superscript</fo:inline>
<fo:inline font-size="0.8em" baseline-shift="sub">Subscript</fo:inline>
</fo:block>
<fo:inline font-weight="bold">Bold</fo:inline>
<fo:inline font-style="italic">Italic</fo:inline>
<fo:inline text-decoration="underline">Underline</fo:inline>
<fo:inline font-family="Courier New" font-size="0.9em">Teletype</fo:inline>
<fo:inline font-size="0.8em" baseline-shift="super">Superscript</fo:inline>
<fo:inline font-size="0.8em" baseline-shift="sub">Subscript</fo:inline>
</fo:block>
という出力を得ることができます.xsl:next-matchが機能しているのがお分かりになりますでしょうか?
このようにな秘密はDITAのDTDにあります.DITAのテンプレートでは、match属性に、*[contans(@class, ' xxx/yyy ')]と書くのがしきたりですが、これはDTDのclass属性が次のように割り当てられているためです.DITAの中間ファイルが作られるとき、パーサーによりこのclass属性の値がつけられます.
<!ATTLIST ph %global-atts; class CDATA "- topic/ph " >
<!ATTLIST b %global-atts; class CDATA "+ topic/ph hi-d/b " >
<!ATTLIST i %global-atts; class CDATA "+ topic/ph hi-d/i " >
<!ATTLIST sub %global-atts; class CDATA "+ topic/ph hi-d/sub ">
<!ATTLIST sup %global-atts; class CDATA "+ topic/ph hi-d/sup ">
<!ATTLIST tt %global-atts; class CDATA "+ topic/ph hi-d/tt " >
<!ATTLIST u %global-atts; class CDATA "+ topic/ph hi-d/u " >
<!ATTLIST b %global-atts; class CDATA "+ topic/ph hi-d/b " >
<!ATTLIST i %global-atts; class CDATA "+ topic/ph hi-d/i " >
<!ATTLIST sub %global-atts; class CDATA "+ topic/ph hi-d/sub ">
<!ATTLIST sup %global-atts; class CDATA "+ topic/ph hi-d/sup ">
<!ATTLIST tt %global-atts; class CDATA "+ topic/ph hi-d/tt " >
<!ATTLIST u %global-atts; class CDATA "+ topic/ph hi-d/u " >
class属性からわかるとおり、b、i、sub、sup、tt、uは、phから派生した要素と考えることができます.上記のスタイルシートは、言ってみればオブジェクトオリエンテッドプログラミング(OOP)で、派生したクラスのメソッドから、super()を呼ぶのにも似ています.
しかし、XSLTはxsl:next-matchを使うときは、注意が必要です.次の優先順位でマッチングするテンプレートは、XSLTプロセッサの判断に委ねられます.priority属性を使って、意図どおりのテンプレートに次の優先順位が決まるようにするなど、コーディングをする方は気をつけなければならないでしょう.