temp\xxx_MERGED.xmlとXPathの効用

昨日の日記で、%DITA-OT%demo\fo\xsl\fo\links.xslを改善した旨を書きましたが、今日はその具体例を少しだけ示します。
改善前のlinks.xslの中には、Relationship Tableによるリンクを処理するための以下のようなコードがあります。

%DITA-OT%demo\fo\xsl\fo\links.xslの抜粋(改善前)
<xsl:template name="createRelatedLinks">
    <xsl:param name="linkType"/>
    <xsl:param name="title"/>
    <xsl:variable name="id" select="@id"/>

    <xsl:if test="$relatedTopicrefs/@id = $id">
        <xsl:variable name="resultLinks">
            <xsl:for-each select="$relatedTopicrefs[@id = $id]">
                <xsl:choose>
                    <xsl:when test="ancestor::*[contains(@class, ' map/reltable ')]/*[contains(@class, ' map/relheader ')]">
                        <xsl:variable name="topicTypeCellSpec" select="ancestor::*[contains(@class, ' map/reltable ')]/*[contains(@class, ' map/relheader ')]/*[contains(@class, ' map/relcolspec ')][@type = $linkType]"/>
                        <xsl:if test="$topicTypeCellSpec">
                            <xsl:variable name="currPosition" select="count(ancestor::*[contains(@class, ' map/relcell ')][1]/preceding-sibling::*) + 1"/>
                            <xsl:variable name="position">
                                <xsl:for-each select="$topicTypeCellSpec">
                                    <xsl:value-of select="count(preceding-sibling::*) + 1"/>
                                </xsl:for-each>
                            </xsl:variable>
                            <xsl:if test="not($currPosition = $position)">
                                <xsl:for-each select="ancestor::*[contains(@class, ' map/relrow ')]/*[contains(@class, ' map/relcell ')][position() = $position]//*[contains(@class, ' map/topicref ')]">
                                    <xsl:variable name="relatedTopic" select="key('key_anchor',@id)[1]"/>
                                    <fo:block xsl:use-attribute-sets="related-links__content">
                                        <fo:basic-link internal-destination="{@id}" xsl:use-attribute-sets="xref">
                                            <xsl:apply-templates select="$relatedTopic/*[contains(@class,' topic/title ')]" mode="insert-text"/>
                                        </fo:basic-link>
                                    </fo:block>
                                </xsl:for-each>
                            </xsl:if>
                        </xsl:if>
                    </xsl:when>
                    <!-- この後、relheaderがなかった場合の処理が続く -->

このコードは、Relationship Tableの情報をopentopic:map/reltableから取ってくるように書かれています。

上記と同等のことを、トピックの末尾にあるrelated-link要素から取得するように変更すると、コードはとてもシンプルで短くなります。なお、xxx_MERGED.xmlにおけるrelated-links要素は、トピックを書くときにrelated-links要素を使って書いたリンクの他に、parent/childリンクおよびRelationship Tableによるリンクの情報も保持しています。

%DITA-OT%demo\fo\xsl\fo\links.xslの抜粋(改善後)
<!-- Relationship Tableによるリンクと、トピックの中のrelated-links要素によるリンクを生成する -->
<xsl:template name="createRelatedLinks">
    <xsl:param name="linkType"/>
    <xsl:param name="title"/>
    <xsl:variable name="id" select="@id"/>

    <!-- Relationship Tableによるリンクのリストを取得する -->
    <xsl:variable name="reltableLinks" select="./*[contains(@class,' topic/related-links ')]//*[contains(@class, ' topic/link ')][@role = 'friend']"/>

    <!-- トピック内のrelated-links要素のリストを取得する -->
    <xsl:variable name="inTopicRelatedLinks" select="./*[contains(@class,' topic/related-links ')]/*[contains(@class,' topic/link ')]"/>

    <xsl:if test="$reltableLinks or $inTopicRelatedLinks">
        <xsl:variable name="resultLinks">
            <xsl:for-each select="$reltableLinks">
                <xsl:if test="@type = $linkType">
                    <!-- ページ番号付きのリンクを出力する -->
                    <xsl:call-template name="createLinkItem">
                        <xsl:with-param name="href" select="@href"/>
                    </xsl:call-template>
                </xsl:if>
            </xsl:for-each>
            <!-- この後、related-link要素によるリンクの処理が続く -->

FOを出力する処理を別のテンプレートを呼び出すように変更していたりするので、元のコードとは書き方が少し違っていますが、基本的は同じような処理を行っています。このXSLTのコードの中で、Relationship Tableによるリンクを取得しているのは、下記のたった1行です。

<xsl:variable name="reltableLinks" select="./*[contains(@class,' topic/related-links ')]//*[contains(@class, ' topic/link ')][@role = 'friend']"/>

Relationship Tableによるリンクの情報を保持しているlink要素はrole属性が"friend"となっているため、上記のようなコードで簡単にRelationship Tableによるリンク情報を取得できます。