Dave
Dave

Reputation: 4694

XSLT apply-templates recursiveness of doom!

I have to following XML document structure:

<option_set id="1">
  <option>Yes</option>
  <option>No</option>
  <option>Maybe</option>
</option_set>

<question option_set="1">
  <text>Do you like cake?</text>
</question>
<question option_set="1">
  <text>Is the cake a lie?</text>
</question>

In the interests of keeping things DRY, the idea is to have a number of different questions which share common sets of options. These can then be built using XSLT. My templates are as follows:

<xsl:template match="question[@option_set and not(option)]">
  <!-- Build a whole question with its options
       (copy the options across and then apply-templates?) -->
</xsl:template>

<xsl:template match="question[option]">
  <!-- Match a whole question, with options, for making pretty HTML out of -->
</xsl:template>

The idea is that once the top template has matched my question, I will be left with something that looks like the following:

<question>
  <text>Do you like cake?</text>
  <option>Yes</option>
  <option>No</option>
  <option>Maybe</option>
</question>

... Which can then be matched by the bottom template and put into my HTML document. My question is how do I create the (top) template that actually does that. I'm close, but this still isn't working:

<xsl:template match="question[@option_set and not(option)]">
  <xsl:variable name="optset" select="@option_set"/>

  <xsl:copy>
    <xsl:copy-of select="text"/>
    <xsl:copy-of select="//option_set[@id=$optset]/option"/>
    <xsl:apply-templates/>
  </xsl:copy>
</xsl:template>

The transformed question block, along with its options is being copied over to the document, instead of being picked up by the top template and made into pretty HTML.

If I try to <xsl:apply-templates select="."/> then I get caught in an infinite loop.

Upvotes: 2

Views: 249

Answers (2)

V a a m Y o b
V a a m Y o b

Reputation: 492

Not sure what you're ultimately trying to do, but this might help you.

<xsl:template match="question">
  <xsl:value-of select="text"/>: 
  <select>
     <xsl:variable name="option_set_id" select="@option_set"/>
     <xsl:apply-templates select="option | //option_set[@id=$option_set_id]/option"/>
  </select>
</xsl:template>

<xsl:template match="option">
   <option>
      <xsl:value-of select="."/>
   </option>
</xsl:template>

There are tweaks, like adding the key above, and checking for unused option_sets etc. but this'll get you started.

Upvotes: 2

Tomalak
Tomalak

Reputation: 338396

<xsl:key name="kOptionSet" match="option_set" use="@id" />

<xsl:template match="question">
  <xsl:copy>
    <xsl:copy-of select="text" />
    <xsl:copy-of select="key('kOptionSet', @option_set)/option" />
    <xsl:apply-templates />
  </xsl:copy>
</xsl:template>

Should pretty much do what you want. I'm not sure why you are recursing in the first place.

Upvotes: 2

Related Questions