Hi I have an xml file which I have to convert to a html-page. The structure of this file is (simplified) like:
<top>
<element>
<option id="SectionA">
<content id="ContentA1"></content>
<content id="ContentA2"></content>
<option id="ContentA3">
<content id="ContentA31"></content>
<content id="ContentA32"></content>
<option id="ContentA33"></option>
</option>
<content id="ContentA4"></content>
</option>
<option id="SectionB">
<content id="ContentA1"></content>
<content id="ContentA2"></content>
</option>
<option id="SectionC">
<content id="ContentA1"></content>
<content id="ContentA2"></content>
</option>
</element>
My XSL file looks like (simplified):
<?xml version="1.0" encoding="utf-8"?>
<xsl:template match="/">
<!-- Output html -->
<xsl:apply-templates select="top/elements"/>
</xsl:template>
<xsl:template match="top/elements">
<xsl:apply-templates select="option" />
</xsl:template>
<xsl:template match="option">
<!-- Output html -->
<xsl:if test="content">
<xsl:apply-templates select="content"/>
</xsl:if>
<xsl:if test="option">
<xsl:apply-templates select="option"/>
</xsl:if>
</xsl:template>
<xsl:template match="content">
<!-- Output html -->
</xsl:template>
Conversions works, but now I have to force the output in such a way, that the order of the elements is respected. As far as I know, using the templates forces the XSL to iterate through all elements which are defined for it. So first <xsl:apply-templates select="content" />
in the option-template will output all content-elements and after that it will output all option-elements (which are on a sublevel). The problem is, I have to maintain the same order as in the XML-document. So the output for sectionA should be:
- ContentA1
- ContentA2
- OptionA3
- ContentA4
Instead of the output of my solution:
- ContentA1
- ContentA2
- ContentA4
- OptionA3
So it will first handle all Content-elements and than the option-elements. How can I force the order which is in the xml for the output?
Your tests are unnecessary: if a node does not exist, then a template matching it will not be executed. Instead of:
you can do simply:
The XSLT processor works through your input XML in document order by default.
All you need to do is use
<xsl:apply-templates />
and get out of the way.To show what I mean, the following simple transformation maps
<element>
to<section>
,<option>
to<div>
and<content>
to<p>
:which results in
A construct like this:
is not really necessary. When there are no
content
nodes,<xsl:apply-templates>
would not have anything to work on, so this would be equivalent:and since you want all the children processed in their original order, it's easiest to do:
or, if you want to be more specific, you can use a union:
This also would maintain input order.