I'm currently building a document in XSL-FO to build a table based on a list of items. The issue is that the items have relationships between them, and I need to be able to reference a value from the other item based on the relationship.
Say I had an input object like:
<Products>
<Product>
<ID>A</ID>
<Name>Cat</Name>
<Relationship>
<ID>B</ID>
</Relationship>
</Product>
<Product>
<ID>B</ID>
<Name>Hat</Name>
</Product>
</Products>
I need to be able to put together a table that has the format of:
Name
----
Cat
- Hat
----
Hat
To build the table rows, I've already done
<fo:table>
<xsl:apply-templates select='Product' />
</fo:table>
and then 'within' each Product, putting a block based on the name:
<fo:block>
<xsl:value-of select="Name" />
</fo:block>
<fo:block>
<xsl:apply-template select="..." />
</fo:block>
My issue is the ...
select option to get the name. I was hoping to be able to build an xpath along the lines of ../Product[ID=./Relationship/ID]/Name
but it doesn't work because the ./
now refers to any of the products, not just the "starting" object.
Is there a way to accomplish this referencing using xpath?
XSLT has a built-in key mechanism to resolve cross-references. Start by defining a key at the top level of your stylesheet as:
<xsl:key name="product" match="Product" use="ID" />
Then, from the context of Product
, you can do:
<xsl:apply-templates select="key('product, Relationship/ID)/Name"/>
Alternatively, you could do:
<xsl:apply-templates select="../Product[ID=current()/Relationship/ID]/Name"/>
But using a key is both more elegant and more efficient.