Jump to content

Displaying Xml Nodes In A Table

Guest David Shepheard

Recommended Posts

Guest David Shepheard

Hi guys,XML structure:

search-results   object1   object2   object3   items	  file-item		 name		 description		 genre	  file-item		 name		 description		 genre	  file-item		 name		 description		 genre


<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:output method="html" encoding="utf-8" omit-xml-declaration="yes"/><xsl:template match="/"><table border="0" id="research" class="style1">  <tr>	<th scope="col">A</th>	<th scope="col">B</th>	<th scope="col">C</th>  </tr>	<xsl:for-each select="search-results/items/file-item">  <tr>	<td><xsl:if test="genre = 'A'"><xsl:value-of select="name"/></xsl:if></td>	<td><xsl:if test="contains(genre, 'B')"><xsl:value-of select="name"/></xsl:if></td>	<td><xsl:if test="genre = 'C'"><xsl:value-of select="name"/></xsl:if></td>  </tr>  </xsl:for-each></table></xsl:template></xsl:stylesheet>

My problem is, that if the first file-item has a genre of "a", its puts it column "a", but then if the next file-item has a genre of "b" (allthough it puts it in the "b" column) it puts it on the next row.The table im getting looks somthing like this:A-----B------Caa-------b-------ba--------------cbut i want it to look like this:A B Ca b ca b cetc...Any help would be much appreciated!!

Edited by David Shepheard
Link to comment
Share on other sites

That's a very interesting issue you have...I can't think of a single transformation that can do it. Consider having two transformations instead: one to turn your XML into one where each genre is grouped under it's own node, and another where each row is composed by taking each node in that intermediate XML.The intermediate XML should look something like:

<file-items>	<genre>		<item>			<name></name>			<description></description>		</item>		<!-- More item elements from this genre -->	</genre>	<!-- More "genre" elements for each genre --></file-items>

from this XML, generating the table should be relatively easy:

<xsl:template match="/">	<table border="0" id="research" class="style1">		<tr>			<th scope="col">A</th>			<th scope="col">B</th>			<th scope="col">C</th>		</tr>		<xsl:for-each select="file-items/genre[1]/item">			<xsl:variable name="pos" select="position()" />			<tr>				<td><xsl:value-of select="name"/></td>				<td><xsl:value-of select="../genre[2]/item[number($pos)]/name"/></td>				<td><xsl:value-of select="../genre[3]/item[number($pos)]/name"/></td>			</tr>		</xsl:for-each>	</table></xsl:template>

Actually getting that intermediate XML is going to be the harder part. Perhaps something like:

<xsl:template match="/">	<file-items>		<genre><xsl:apply-templates select="search-results/items/file-item[genre='A']" /></genre>		<genre><xsl:apply-templates select="search-results/items/file-item[genre='B']" /></genre>		<genre><xsl:apply-templates select="search-results/items/file-item[genre='C']" /></genre>	</file-items></xsl:template><xsl:template match="*"><xsl:copy><xsl:apply-templates/></xsl:copy></xsl:template><xsl:template match="file-item"><item><xsl:apply-templates match="*[local-name() != 'genre']" /></item></xsl:template>

Link to comment
Share on other sites

  • 3 weeks later...

This may work for you, It does not require an intermediate step. It automatically determines the largest number of any one item and builds a corresponding table. It does rely on the MSXML node-set function and it is hard coded for three genres. These could be revised and streamlined if needed, but maybe this can get you started.

Sample XML		<table>			<genre>C</genre>			<genre>B</genre>			<genre>A</genre>			<genre>A</genre>			<genre>A</genre>			<genre>B</genre>			<genre>C</genre>			<genre>A</genre>			<genre>B</genre>			<genre>B</genre>			<genre>B</genre>			<genre>B</genre>		</table>

		<xsl:stylesheet			xmlns:xsl="http://www.w3.org/1999/XSL/Transform"			xmlns:msxsl="urn:schemas-microsoft-com:xslt"			version="1.0">			<xsl:output method="html" />		<xsl:template match="/">			<xsl:variable name="GenreCount">				<top>					<count> <xsl:value-of select="count(//genre[text()='A'])" /> </count>					<count> <xsl:value-of select="count(//genre[text()='B'])" /> </count>					<count> <xsl:value-of select="count(//genre[text()='C'])" /> </count>				</top>			</xsl:variable>			<xsl:variable name="IndexCount">				<xsl:for-each select="msxsl:node-set($GenreCount)//count">					<xsl:sort select="text()" order="descending"/>					<xsl:if test="position()=1">						<xsl:value-of select="text()"/>					</xsl:if>				</xsl:for-each>.			</xsl:variable>			<table border="1">			<xsl:call-template name="DoRow">				<xsl:with-param name="IndexCount" select="$IndexCount"/>			</xsl:call-template>			</table>		</xsl:template>		<xsl:template name="DoRow">			<xsl:param name="IndexCount"/>			<xsl:param name="index" select="1"/>			<tr>				<td><xsl:value-of select="//genre[text()='A'][$index]/text()"/></td>				<td><xsl:value-of select="//genre[text()='B'][$index]/text()"/></td>				<td><xsl:value-of select="//genre[text()='C'][$index]/text()"/></td>			</tr>			<xsl:if test="$index < $IndexCount" >				<xsl:call-template name="DoRow">					<xsl:with-param name="IndexCount" select="$IndexCount"/>					<xsl:with-param name="index" select="$index + 1"/>				</xsl:call-template>			</xsl:if>		</xsl:template>

produces:A B C A B C A B - A B - - B - - B -(- added as placeholder, will not appear in output)

Edited by aalbetski
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Create New...