Reputation: 12347
I have an xml where element names under client/product/analytics/count
is unknown. Is there a way I can traverse and get each element name and it's equivalent value?
below is my xml data
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="client.xsl"?>
<client version="1.0">
<product>
<analytics>
<count>
<SkinsCount>14</SkinsCount>
<AppsCount>6</AppsCount>
<AbspCount>2</AbspCount>
</count>
</analytics>
</product>
</client>
part of my xsl code
...
<xsl:variable name="NA" select="'no data'" />
<h3><span style="color:#328aa4"><a name="_analytics" href="#_top">Analytics </a></span></h3>
<h3>Count</h3>
<dd><br/>
<xsl:choose>
<xsl:when test="client/product/analytics/count/*">
<table border="1">
<tbody>
<xsl:if test="client/product/analytics/count/AbspCount"><tr>
<th align="left">Absp Count</th><td><xsl:value-of select="client/product/analytics/count/AbspCount"/></td></tr>
</xsl:if>
<xsl:if test="client/product/analytics/count/SkinsCount"><tr>
<th align="left">Skins Count</th><td><xsl:value-of select="client/product/analytics/count/SkinsCount"/></td></tr>
</xsl:if>
<xsl:if test="client/product/analytics/count/AppsCount"><tr>
<th align="left">Apps Count</th><td><xsl:value-of select="client/product/analytics/count/AppsCount"/></td></tr>
</xsl:if>
</tbody>
</table>
</xsl:when>
<xsl:otherwise>
<br/><xsl:value-of select="$NA"/>
</xsl:otherwise>
</xsl:choose>
</dd>
...
for which current output snapshot when I specifically use known element names like AppsCount, AbspCount & SkinsCount
Upvotes: 0
Views: 832
Reputation: 70598
You should probably start off by simply selecting all the child elements of the count element
<xsl:apply-templates select="client/product/analytics/count/*" />
Then you would have a single template to match such elements, and output the element name and value, like so
<xsl:template match="count/*">
<tr>
<td><xsl:value-of select="local-name()" /></td>
<td><xsl:value-of select="." /></td>
</tr>
</xsl:template>
Of course, this will output the element name without spaces (i.e as "SkinsCount"). If the element names always ended in "Count", you could do this
<xsl:value-of select="concat(substring-before(local-name(), 'Count'), ' Count')" />
But if you were using XSLT 2.0, you could you make use of xsl:analyze-string to split up the element name based of the capitalised letters.
Try this XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes" />
<xsl:template match="/">
<table>
<xsl:apply-templates select="client/product/analytics/count/*" />
</table>
</xsl:template>
<xsl:template match="count/*">
<tr>
<td>
<xsl:analyze-string select="local-name()" regex="[A-Z][a-z0-9]*">
<xsl:matching-substring>
<xsl:value-of select="concat(., ' ')" />
</xsl:matching-substring>
</xsl:analyze-string>
</td>
<td><xsl:value-of select="." /></td>
</tr>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1
Reputation: 116959
Try something like:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<table border="1">
<xsl:for-each select="client/product/analytics/count/*">
<tr>
<th align="left"><xsl:value-of select="name()"/></th>
<td><xsl:value-of select="."/></td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
Upvotes: 2