Link to home
Start Free TrialLog in
Avatar of DigitalCandyMan
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>


Avatar of rdcpro
rdcpro
Flag of United States of America image

A good use of non-muenchian grouping.  This one can be done simply with XPath.  Here's an example that does essentially what you want (I'm breaking the table up into "n" tds) but you can set n to be

ceiling(count(mainItem/item/Title))

Here's the example:

http://dev.rdcpro.com/Members/rdcpro/snippets/xpathgrouping/

Regards,
Mike Sharp
Avatar of DigitalCandyMan
DigitalCandyMan

ASKER

ok.. I'll look into that.. but "CAN" this be acccomplished with an XSL stylesheet instead?
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


ASKER CERTIFIED SOLUTION
Avatar of rdcpro
rdcpro
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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
Ok.. here's the latest. (XML sample is below)
<xsl:variable name="TotalHotels" select="count(/destination/destinations/destination/property)"/>
      <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/destinations/destination/property">
            <hotels>
                  <xsl:apply-templates select="property"/>
            </hotels>
      </xsl:template>
      <xsl:template match="/destination/destinations/destination/property">
            <HotelsA>
                  <xsl:if test="destinations/destination/@linkable[. != '1'] or property/@name[. != '']">
                        <xsl:apply-templates select="msxsl:node-set($SortedHotels)/name[position() &lt; $TotalHotels div 2]"/>
                  </xsl:if>      
            </HotelsA>
            <HotelsB>
                  <xsl:apply-templates select="msxsl:node-set($SortedHotels)/name[position() &gt; $TotalHotels div 2]"/>
            </HotelsB>
      </xsl:template>
      <xsl:template match="/destination/destinatins/destination/property">
            <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/destinations/destination/property">
              <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/destinations/destination/property">
            <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
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=547891">HOTEL NAME F</a>

I will look at your code again... Thanks! :)