Search code examples
xsltxsl-foapache-fop

Is it possible to determine a key's position in a list in an XSL-FO stylesheet?


I've got a list of objects that I'm referencing by a <xsl:key>, and I'm trying to figure out the order of the referred-to objects within an <xsl:value-of> (or similar block).

I have the following XML:

<document>
  <question>
    <text>Please demonstrate your compliance with some boring standard.</text>
    <answer>
      <attachment ref="11111111-2222-3333-4444-555555555555"/>
      <attachment ref="22222222-3333-4444-5555-666666666666"/>
    </answer>
  </question>
  <question>
    ...
  </question>

  <attachment id="11111111-2222-3333-4444-555555555555">
    <name>employee_names_and_titles.doc</name>
    ...
  </attachment>
  <attachment id="22222222-3333-4444-5555-666666666666">
    <name>standard_operating_procedures.doc</name>
    ...
  </attachment>
</document>

And the following XSLT:

<!-- Page Layout -->
<xsl:template match="document">
  <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
    <fo:layout-master-set>
      <fo:simple-page-master master-name="usLetter" page-height="11in" page-width="8.5in" margin-top="0.5in" margin-bottom="1in" margin-left="0.5in" margin-right="0.5in">
        <fo:region-body/>
      </fo:simple-page-master>
    </fo:layout-master-set>
    <fo:page-sequence master-reference="usLetter">
      <fo:flow flow-name="xsl-region-body">
        <xsl:apply-templates/>
      </fo:flow>
    </fo:page-sequence>
  </fo:root>
</xsl:template>

<!-- Question and Answer section -->
<xsl:template match="question">
  <fo:block font-weight="bold">
    <xsl:value-of select="text"/>
  </fo:block>
  <fo:block>
    <xsl:apply-templates/>
  </fo:block>
</xsl:template>

<xsl:template match="question/answer">
  <fo:block>
    <xsl:apply-templates/>
  </fo:block>
</xsl:template>

<xsl:template match="answer/attachment">
  <fo:block>
    Refer to <xsl:value-of select="key('attachments', @ref)/name"/>
  </fo:block>
</xsl:template>

<!-- Appendix section -->
<xsl:key name="attachments" match="document/attachment" use="@id"/>

<xsl:template match="survey/attachment">
  <fo:block break-before="page" font-size="20pt" font-weight="bold">
    Appendix <xsl:number format="A"/>
  </fo:block>
  <fo:block>
    ...
  </fo:block>
</xsl:template>

My desired document layout is to have all of the questions and answers within one flow, with answers frequently referencing things that appear in a later appendix. In the appendix, each "attachment" should be on it's own page, and each attachment should be numbered incrementally.

All of this is happening as expected; however, the answer currently says Refer to employee_names_and_titles.doc, when what I'd really like is for it to say Refer to Appendix A.

Is there a way that I can figure out the position of attachment ref="1111..." in the list of attachments, within the scope of the question-and-answer section? Is there a better way of formatting my XML, so that perhaps I won't have this problem?


Solution

  • Is there a way that I can figure out the position of attachment ref="1111..." in the list of attachments

    You can count its preceding attachment siblings, for example:

    <xsl:template match="answer/attachment">
      <fo:block>
       Refer to Appendix <xsl:number value="count(key('attachments', @ref)/preceding-sibling::attachment) + 1" format="A"/>
      </fo:block>
    </xsl:template>