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によるリンク情報を取得できます。