tags:

views:

490

answers:

2

I am trying to generate HTML which will display the data from XML through XSLT. The XML contains heading tags that are dynamically generated, like h1, h2, h3, h4 etc.

Now in XSLT I want to dynamically access the h1, h2 and h3 in single for-each as the heading can be lesser in level, for example h1, h2 only or can be deeper in level like h1, h2, h3 and h4.

The output HTML may look like:

                           h1_value1                                h1_value2
           h2_valu1                       h2value3            ....            .....
h3_value1  h3_value2  h3_value3      h3_value4  h3_value5     ....            .....

My XSLT contains a variable that is incremented up to the number of levels which we have already counted. It means that if there are 3 levels then there will h1, h2 and h3 tags in XML. So to access these tags I used concat() function in select of for-each and concatenated "h" with the variable, say j. The template will be recursively called and every time j will be increased by 1 up to the number of levels.

But using a concat() function in select of for-each gives an uncaught error. Can't I use the concat() function in select of for-each or use a variable in select of for-each that is using the concat() function?

A: 
Filburt
Thank you for replying, My XML file looks like this<?xml version="1.0"?><matrix> <x-depth>3</x-depth> <y-depth>2</y-depth> <number-of-measure>2</number-of-measure> <h> <h1> <title colspan="2">Region A</title> <title colspan="2">Region B</title> </h1> <h2> <title colspan="3">Prod Cat 1</title> <title colspan="3">Prod Cat 2</title> <title colspan="2">Prod Cat 3</title> </h2> <h3> <title>p1</title> <title>p2</title> <title>p3</title> <title>p4</title> </h3> </h></matrix>and in XSLT trying to get h1, h2, h3 etc in single for-each using concat().
Bhushan Sarwade
In my XSLT I am doing something like this:<tr> <xsl:call-template name="v-depth"> <xsl:with-param name="count"><xsl:value-of select="/matrix/y-depth" /></xsl:with-param> </xsl:call-template> <xsl:variable name="concat_path" select="concat('/matrix/h/h',$j,'/title')" /> <td><xsl:value-of select="$concat_path" /></td> <xsl:for-each select="$concat_path"> <th> <xsl:value-of select="current()" /> </th> </xsl:for-each> </tr>This <tr> is inside a template that is called recursively till the counter ends.
Bhushan Sarwade
I'm afraid, i still don't fully comprehend what you are trying to achieve, but is suspect you would be better off not to rely on using a counter. Could **xsl:sort**-ing your hXX nodes be a possible way?
Filburt
Thanks Filburt, this is what I want. Because I am a Java/Oracle programmer I am thinking in a traditional way. the solution you have given is not generating exactly what I need but it gave me something to think in a different way.
Bhushan Sarwade
I guess the numbers are padded to 'h' for sorting purposes. If you can change the PL/SQL program to put the sorting index into an attribute like <h sortindex="1"><title colspan="2">Region A</title></h> the xslt for sorting would be even easier.
Filburt
+2  A: 

You can't

<xsl:for-each select="concat('h', $number)">
</xsl:for-each>

but you can

<xsl:for-each select="*[name() = concat('h', $number)]">
</xsl:for-each>

XPath functions may only be used in node tests (the parts of the expression within square brackets), but not in location steps.

First you must locate nodes in a location step (the * does that here, selecting all child nodes - but you can use any XPath), then you can test a condition on them, for example checking their name.

Tomalak
Thank you, This helped me. But the tags h1, h2, h3 etc in my XML file are added from a PL/SQL program. Sometimes their might be only h1 or h1, h2 or might be h1, h2, h3, h4 in that case I am setting another tag named as x-depth. This is my counter in XSLT which I want to concat with "h", so I can dynamically fetch the data from XML, never mind how many "hXX" tags are in my XML. In above mentioned solution I will have to specify which "hXX" currently I want to fetch like "matrix/h/h1[name() = concat('h', $j)]/title"and that I don't know. So need some other to do this..
Bhushan Sarwade
`matrix/h/*[name() = concat('h', $j)]/title`
Tomalak
Thank you Tomalak and please excuse for the formatting, I am new to this forum not yet familiar with the tool set facilities. So can we make the for-each dynamic in any other way?
Bhushan Sarwade
I'm not sure if I understand you (or you me). Yes, by all means you can make the XPath in the for-each select dynamic. The XPath to do so is in my comment two steps up.
Tomalak
My Mistake, I missed the * you have added, it worked thank you very much. For reference The final code looks like:<xsl:template name="h-title"> <xsl:param name="j" /> <xsl:param name="i" /> <xsl:if test="$j <= $i"> <tr> <xsl:for-each select="matrix/h/*[name() = concat('h', $j)]/title"> <th> <xsl:if test="@colspan > 0"> <xsl:attribute name="colspan"><xsl:value-of select="@colspan"/></xsl:attribute> </xsl:if> <xsl:value-of select="current()" /> </th> </xsl:for-each></tr> </xsl:if>continued...
Bhushan Sarwade
<xsl:if test="$j <= $i"> <xsl:call-template name="h-title"> <xsl:with-param name="j"><xsl:value-of select="$j + 1" /></xsl:with-param> <xsl:with-param name="i"><xsl:value-of select="$i" /></xsl:with-param> <xsl:with-param name="vpath"><xsl:value-of select="concat('/matrix/h/h',$j,'/title')" /></xsl:with-param> </xsl:call-template> </xsl:if> </xsl:template>
Bhushan Sarwade
If it worked, please mark the answer as accepted. ;-)
Tomalak