DigitalCandyMan
asked on
Split XML into two TD's with XSL
I have an xml file that I need so split into two tables. Such as:
<mainItem>
<item>
<Title>NameA</Title>
<Title>NameB</Title>
<Title>NameC</Title>
<Title>NameD</Title>
<Title>NameE</Title>
<Title>NameF</Title>
<Title>NameG</Title>
<Title>NameH</Title>
<Title>NameI</Title>
<Title>NameJ</Title>
<Title>NameK</Title>
</item>
<mainItem>
I want to take the FIRST half (in order) and place it into a table's TD , and the second half into another TD, SORTED by original order. I know I need to count the total items in the node and then take half. I've been able to use count() and DIV (divide) - using a variable- to get the total and what is half (in this case 5.5 or 6) but I can't seem to get the xsl to search for the half way point and then select 1-5 for the 1st TD and 6-11 for the 2nd TD. Like this:
<table>
<tr>
<td>
NameA<br>
NameB<br>
NameC<br>
NameD<br>
NameE<br>
</td>
<td>
NameF<br>
NameG<br>
NameH<br>
NameI<br>
NameJ<br>
NameK<br>
</td>
</tr>
</table>
<mainItem>
<item>
<Title>NameA</Title>
<Title>NameB</Title>
<Title>NameC</Title>
<Title>NameD</Title>
<Title>NameE</Title>
<Title>NameF</Title>
<Title>NameG</Title>
<Title>NameH</Title>
<Title>NameI</Title>
<Title>NameJ</Title>
<Title>NameK</Title>
</item>
<mainItem>
I want to take the FIRST half (in order) and place it into a table's TD , and the second half into another TD, SORTED by original order. I know I need to count the total items in the node and then take half. I've been able to use count() and DIV (divide) - using a variable- to get the total and what is half (in this case 5.5 or 6) but I can't seem to get the xsl to search for the half way point and then select 1-5 for the 1st TD and 6-11 for the 2nd TD. Like this:
<table>
<tr>
<td>
NameA<br>
NameB<br>
NameC<br>
NameD<br>
NameE<br>
</td>
<td>
NameF<br>
NameG<br>
NameH<br>
NameI<br>
NameJ<br>
NameK<br>
</td>
</tr>
</table>
ASKER
ok.. I'll look into that.. but "CAN" this be acccomplished with an XSL stylesheet instead?
ASKER
I noticed in your sample that it only seems to group the values of each node ('date;, "pg" etc) - and place them into separate TD's... I need to COUNT the total and split that in half THEN put the first half in td 1 and the 2nd half in TD 2... I'll try to be more explicit..
If you have and xml file that describes an unknown quantity pencils - of which one of the elements in the xml is the color of the pencil. I need to count the total number in the node (How many are there?) and then sort by color name, then split that in two..without changing the original order.
The list: (in this case ther are 8)
Red
Blue
Green
Yellow
Blue-green
Rose
Aqua
Purple
Sorted:
RED
Aqua
Blue
Blue-green
Green
Purple
Rose
Yellow
First Half (4, into TD #1)
RED
Aqua
Blue
Blue-green
Second Half (4, into TD #2)
Green
Purple
Rose
Yellow
If you have and xml file that describes an unknown quantity pencils - of which one of the elements in the xml is the color of the pencil. I need to count the total number in the node (How many are there?) and then sort by color name, then split that in two..without changing the original order.
The list: (in this case ther are 8)
Red
Blue
Green
Yellow
Blue-green
Rose
Aqua
Purple
Sorted:
RED
Aqua
Blue
Blue-green
Green
Purple
Rose
Yellow
First Half (4, into TD #1)
RED
Aqua
Blue
Blue-green
Second Half (4, into TD #2)
Green
Purple
Rose
Yellow
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thans Mike.. you've been quite helpful.. but I'm still having problems.. I do see what you're doing with the code. But I can't seem to get your example to output - as indicated. I copied the text and made both (xslt and xml) files - but the XML won't parse in my IE6. When I try your samples (chaned of couse to match the XML fiile i'm working with I get errors..such as I can't have templates inside templates. Any thoughts?
No, you can't have templates inside of templates. You don't nest templates. The code above is tested and works with IE6.
Post your code, and I'll tell you what's wrong.
Regards,
Mike Sharp
Post your code, and I'll tell you what's wrong.
Regards,
Mike Sharp
ASKER
Ok.. here's the latest. (XML sample is below)
<xsl:variable name="TotalHotels" select="count(/destination /destinati ons/destin ation/prop erty)"/>
<xsl:variable name="SortedHotels">
<xsl:for-each select="@name">
<xsl:sort select="@name"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:variable>
<xsl:template match="/destination/destin ations/des tination/p roperty">
<hotels>
<xsl:apply-templates select="property"/>
</hotels>
</xsl:template>
<xsl:template match="/destination/destin ations/des tination/p roperty">
<HotelsA>
<xsl:if test="destinations/destina tion/@link able[. != '1'] or property/@name[. != '']">
<xsl:apply-templates select="msxsl:node-set($So rtedHotels )/name[pos ition() < $TotalHotels div 2]"/>
</xsl:if>
</HotelsA>
<HotelsB>
<xsl:apply-templates select="msxsl:node-set($So rtedHotels )/name[pos ition() > $TotalHotels div 2]"/>
</HotelsB>
</xsl:template>
<xsl:template match="/destination/destin atins/dest ination/pr operty">
<xsl:copy-of select="."/>
</xsl:template>
----------
XML Sample
<destination code="RESORTCODE" name="RESORT NAME" >
<description>
<![CDATA[Desriptve text removed.]]>
</description>
<destinations>
<destination code="HOTEL GROUP NAME" name="Hotel Name Area 1" linkable="0" >
<property code="1235" name="Hotel Name B"/>
<property code="123456" name="Hotel Name C" />
<property code="265789" name="Hotel Name D" />
<property code="89745" name="Hotel Name E" />
<property code="547891" name="Hotel Name F" />
</destination>
<destination code="HOTEL GROUP NAME 2" name="Hotel Name Area 2" linkable="0">
<property code="ada458" name="Hotel Name X" />
<property code="afa5897" name="Hotel Name Y" />
</destination>
</destinations>
</destination>
<xsl:variable name="TotalHotels" select="count(/destination
<xsl:variable name="SortedHotels">
<xsl:for-each select="@name">
<xsl:sort select="@name"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:variable>
<xsl:template match="/destination/destin
<hotels>
<xsl:apply-templates select="property"/>
</hotels>
</xsl:template>
<xsl:template match="/destination/destin
<HotelsA>
<xsl:if test="destinations/destina
<xsl:apply-templates select="msxsl:node-set($So
</xsl:if>
</HotelsA>
<HotelsB>
<xsl:apply-templates select="msxsl:node-set($So
</HotelsB>
</xsl:template>
<xsl:template match="/destination/destin
<xsl:copy-of select="."/>
</xsl:template>
----------
XML Sample
<destination code="RESORTCODE" name="RESORT NAME" >
<description>
<![CDATA[Desriptve text removed.]]>
</description>
<destinations>
<destination code="HOTEL GROUP NAME" name="Hotel Name Area 1" linkable="0" >
<property code="1235" name="Hotel Name B"/>
<property code="123456" name="Hotel Name C" />
<property code="265789" name="Hotel Name D" />
<property code="89745" name="Hotel Name E" />
<property code="547891" name="Hotel Name F" />
</destination>
<destination code="HOTEL GROUP NAME 2" name="Hotel Name Area 2" linkable="0">
<property code="ada458" name="Hotel Name X" />
<property code="afa5897" name="Hotel Name Y" />
</destination>
</destinations>
</destination>
You have a number of errors in your XSLT. Most of them are because you have the node context wrong.
1. For example, this:
<xsl:variable name="SortedHotels">
<xsl:for-each select="@name">
<xsl:sort select="@name"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:variable>
can't work because there is no context. There can only be one attribute with given name in any element. Perhaps you meant:
<xsl:variable name="SortedHotels">
<xsl:for-each select="destination/destin ations/des tination/p roperty">
<xsl:sort select="@name"/>
<name><xsl:value-of select="@name"/></name>
</xsl:for-each>
</xsl:variable>
2. This also has a context problem:
<xsl:template match="/destination/destin ations/des tination/p roperty">
<hotels>
<xsl:apply-templates select="property"/>
</hotels>
</xsl:template>
The current context in this template is the current <property>. So calling:
<xsl:apply-templates select="property"/>
doesn't find any <property> child nodes.
3. You have two templates which match the same node. The XSLT will only ever use one of them. Use the Mode attribute, or modify your match expressions to set template priority.
there are lots of similar problems...take a closer look at my original code.
Regards,
Mike Sharp
1. For example, this:
<xsl:variable name="SortedHotels">
<xsl:for-each select="@name">
<xsl:sort select="@name"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:variable>
can't work because there is no context. There can only be one attribute with given name in any element. Perhaps you meant:
<xsl:variable name="SortedHotels">
<xsl:for-each select="destination/destin
<xsl:sort select="@name"/>
<name><xsl:value-of select="@name"/></name>
</xsl:for-each>
</xsl:variable>
2. This also has a context problem:
<xsl:template match="/destination/destin
<hotels>
<xsl:apply-templates select="property"/>
</hotels>
</xsl:template>
The current context in this template is the current <property>. So calling:
<xsl:apply-templates select="property"/>
doesn't find any <property> child nodes.
3. You have two templates which match the same node. The XSLT will only ever use one of them. Use the Mode attribute, or modify your match expressions to set template priority.
there are lots of similar problems...take a closer look at my original code.
Regards,
Mike Sharp
ASKER
Yes.. there is no context in the nodes. All the information being used in the website is contained in the value of the attributes like this:
<property code="547891" name="Hotel Name F" /> which would then need to be displayed on screen as "HOTEL NAME F"
as a hyperlink:
<a href="filename.aspx?code=5 47891">HOT EL NAME F</a>
I will look at your code again... Thanks! :)
<property code="547891" name="Hotel Name F" /> which would then need to be displayed on screen as "HOTEL NAME F"
as a hyperlink:
<a href="filename.aspx?code=5
I will look at your code again... Thanks! :)
ceiling(count(mainItem/ite
Here's the example:
http://dev.rdcpro.com/Members/rdcpro/snippets/xpathgrouping/
Regards,
Mike Sharp