XSL-FOに入力XMLの階層を出力する。

XSL-FOに出力するのですが、入力XMLが複雑すぎて、どのFOが何から作られているのかわからなくなる場合があります。このようなときに、そのオブジェクトを作った元のデータの階層をxsl:commentでFOに出しておくと解析に便利です。

例えば

    <xsl:template match="~">
        <xsl:comment><xsl:value-of select="ahf:getHistory(.)"></xsl:value-of></xsl:comment>
        <fo:block-container>
           ...
        </fo:block-container>
    </xsl:template>

などとやります。ahf:getHistoryの実装は以下のような感じです。

    <!-- 
     function:  Get element history string
     param:     prmElem
     return:    xs:string
     note:
     -->
    <xsl:function name="ahf:getHistory" as="xs:string">
        <xsl:param name="prmElem" as="element()"/>
        <xsl:variable name="ancestorElem" as="element()+" select="$prmElem/ancestor-or-self::*"/>
        <xsl:variable name="historyStr" as="xs:string*">
            <xsl:for-each select="$ancestorElem">
                <xsl:variable name="elem" select="."/>
                <xsl:variable name="name" as="xs:string" select="name()"/>
                <xsl:sequence select="if (position() gt 1) then '/' else ''"/>
                <xsl:sequence select="local-name()"/>
                <xsl:sequence select="if (exists($elem/parent::*)) then concat('[',string(count($elem/preceding-sibling::*[name() eq $name]) + 1),']') else ''"/>
            </xsl:for-each>
        </xsl:variable>
        <xsl:sequence select="string-join($historyStr,'')"/>
    </xsl:function>


これで

<!--document/chapter[2]/section[6]/p[1]/line[2]/text[1]--> 
<fo:block-container absolute-position="absolute"
                    top="0pt"
                    bottom="0pt"
                    left="0pt"
                    right="0pt"
                    font-family="MS-Mincho"
                    font-size="10.500000pt"
                    color="#ff0000">

などと出てくれます。結構便利に使っています。