Reputation: 6437
I am looking to find out how to apply a template to an XML file, based on a parameter in the XML file.
The XML file has the following format :
<workfile>
<query>
<some-info-1/>
<some-info-2/>
<some-info-3/>
<some-info-4/>
<some-info-5/>
<some-info-6/>
<some-info-7/>
<parameter name="hours-min" value="7" />
<parameter name="hours-max" value="9" />
<parameter name="output-type" value="type-1" />
</query>
</workfile>
The XML file is generated by another program, and requires a specific output format depending on the value of the parameter "output-type". This parameter can occur several times, if the results have to be generated for several outputs at the same time, so will require a for-each
loop.
Edit Here is an example with several output-type parameters :
<workfile>
<query>
<some-info-1/>
<some-info-2/>
<some-info-3/>
<parameter name="hours-min" value="7" />
<parameter name="hours-max" value="9" />
<parameter name="output-type" value="type-1" />
<parameter name="output-type" value="type-2" />
<parameter name="output-type" value="type-3" />
</query>
</workfile>
I would like to create a main template file generate-main.xsl
and, in the file, import/include the other template files (generate-type-1.xsl, generate-type-2.xsl, and so on). Each of these templates will have to work from the root node (/
). But I am having issues conceiving how to do this.
This is the generate-main.xsl
base I wrote :
<xsl:template match="/">
<results>
<xsl:for-each select="/workfile/query/parameter[@name='output-type']">
<xsl:variable name="outputType" select="./@value" />
<xsl:choose>
<xsl:when test="$outputType='type-1'">
<xsl:call-template name="type-1" />
</xsl:when>
<xsl:when test="$outputType='type-2'">
<xsl:call-template name="type-2" />
</xsl:when>
<xsl:when test="$outputType='type-3'">
<xsl:call-template name="type-3" />
</xsl:when>
<xsl:when test="$outputType='type-4'">
<xsl:call-template name="type-4" />
</xsl:when>
<xsl:when test="$outputType='type-5'">
<xsl:call-template name="type-5" />
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</results>
</xsl:template>
<xsl:template name="type-1">
<!-- TO DO -->
</xsl:template>
<xsl:template name="type-2">
<!-- TO DO -->
</xsl:template>
<xsl:template name="type-3">
<!-- TO DO -->
</xsl:template>
<xsl:template name="type-4">
<!-- TO DO -->
</xsl:template>
<xsl:template name="type-5">
<!-- TO DO -->
</xsl:template>
</xsl:stylesheet>
I did do research on this. For example, Dimitre Novatchev answered this question for when templates are in the same XSL file (Applying different XSLT template depending on a parameter), but I didn't find how I would be able to do so with imported XSL files that work from the root node.
So my questions are :
1) Is it possible to include or import templates into a main XSL file and only call one depending on a parameter (for example, by playing the include inside the called template?)
2) Is it still possible if all included templates work with the root node (and, I would assume, start with <template match="/">
)?
Any help would be much appreciated.
Anton Harris
Upvotes: 0
Views: 1187
Reputation: 117003
I think there are two questions here:
The answer to the first question is definitely yes. You can include other stylesheets in your main stylesheet and call their templates in the same manner as templates in the main stylesheet. And each template can select whatever it needs to select - including starting from the root, if necessary.
Note that the included stylesheets are included always - with no regard to what happens at runtime. You can decide whether to use them, according to the input; but they will always be there.
The answer to the second question is more difficult, because the description is too abstract. I suspect you could get more mileage out of a single "output" template, called several times - each time with a different parameter. Then use the choose
element inside the template to produce the appropriate output.
Upvotes: -1
Reputation: 163352
Include and import work at compile time, when there is no source document available, so you can't import or include things based on what you find in the data (unless you want to get into dynamic stylesheet generation, which I doubt is appropriate here).
It's not clear to me why you can't solve the problem using the standard apply-templates mechanism. Replace this stuff:
<xsl:for-each select="/workfile/query/parameter[@name='output-type']">
<xsl:variable name="outputType" select="./@value" />
<xsl:choose>
<xsl:when test="$outputType='type-1'">
<xsl:call-template name="type-1" />
</xsl:when>
<xsl:template name="type-1">
<!-- TO DO -->
</xsl:template>
(which is very un-XSLT-like, and verbose)
with
<xsl:apply-templates select="/workfile/query/parameter[@name='output-type']"/>
<xsl:template match="parameter[@name='output-type'][@value='type1']">
<!-- TO DO -->
</xsl:template>
etc.
Why would you want all included templates to start at the root node?
Upvotes: 2