Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
|
XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old July 11th, 2011, 02:17 AM
Authorized User
 
Join Date: Jan 2010
Posts: 32
Thanks: 0
Thanked 0 Times in 0 Posts
Default XSLT keys help

Hi,

I am trying to generate a table of output derived from two xmls using document() function in XSLT.

I have two xmls attached (xml1.txt), (xml2.txt).

I would like to get a key list of dates from both XMLs and align the data in a table in the output. Sometimes it is possible that the date Entry in first xml may not have a corresponding date entry in the second XML and vice versa.

xml1

Code:
<?xml version="1.0" encoding="utf-8"?>
<Items>
  <Item>
    <Date>
      10/12/2010
    </Date>
    <Name>
      A1
    </Name>
    <FathersName>
      A
    </FathersName>
    <Address>xxx</Address>
    <Occupation>Engineer</Occupation>
  </Item>
  <Item>
    <Date>
      10/15/2010
    </Date>
    <Name>
      A2
    </Name>
    <FathersName>
      A2 Father
    </FathersName>
    <Address>A2 Address</Address>
    <Occupation>Sales Professional</Occupation>
  </Item>

  and so on...
</Items>
xml2

Code:
<?xml version="1.0" encoding="utf-8"?>
<Items>
  <Item>
    <Date>
      10/12/2010
    </Date>
    <Result1>0.1</Result1>
    <Result2>0.4</Result2>
    <Result3>0.5</Result3>
  </Item>
  <Item>
    <Date>
      10/17/2010
    </Date>
    <Result1>0.1</Result1>
    <Result2>0.4</Result2>
    <Result3>0.6</Result3>
  </Item>

  <Item>
    <Date>
      10/19/2010
    </Date>
    <Result1>
      0.008
    </Result1>
    <Result2>
      0.005
    </Result2>
    <Result3>
      0.006
    </Result3>
  </Item>



  and so on...
</Items>
Output

Code:
<table>
<theader>
<td>Date</td>
<td>Name</td>
<td>FathersName</td>
<td>Occupation</td>
<td>Result1</td>
<td>Result2</td>
<td>Adress</td>
<td>Result3</td>
</theader>

<tr>
<td>10/12/2010</td>
<td>A1</td>
<td>A</td>
<td>Engineer</td>
<td>0.1</td>
<td>0.4</td>
<td>xxx</td>
<td>0.5</td>
</tr>

<tr>
<td>10/15/2010
</td>

<td>A2</td>
<td>A2Father</td>
<td>SalesProfessional</td>

<td>-</td>
<td>-</td>
<td>A2 Address
</td>
<td>-</td>
</tr>

<tr>
<td>10/17/2010
</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>0.1</td>
<td>0.4</td>
<td>-</td>
<td>0.5</td>
</tr>

<tr>
<td>10/19/2010
</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>0.008</td>
<td>0.005</td>
<td>-</td>
<td>0.006</td>
</tr>


</table>


Thanks,
 
Old July 11th, 2011, 06:08 AM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

Here is an XSLT 2.0 solution not using keys but rather for-each-group:
Code:
<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xs"
  version="2.0">
  
  <xsl:output method="html" indent="yes"/>
  <xsl:strip-space elements="*"/>
    
  <xsl:param name="cols" 
    select="'Date', 'Name', 'FathersName', 'Occupation', 'Result1', 'Result2', 'Address', 'Result3'"/>
  
  <xsl:param name="url2" select="'test2011071102.xml'"/>
  <xsl:variable name="doc2" select="document($url2)"/>
  
  <xsl:template match="Items">
    <table>
      <thead>
        <tr>
          <xsl:for-each select="$cols">
            <th>
              <xsl:value-of select="."/>
            </th>
          </xsl:for-each>
        </tr>
      </thead>
      <tbody>
        <xsl:for-each-group select="Item, $doc2/Items/Item" group-by="normalize-space(Date)">
          <tr>
            <xsl:for-each select="$cols">
              <td>
                <xsl:value-of select="normalize-space((current-group()/*[local-name() eq current()], '-')[1])"/>
              </td>
            </xsl:for-each>
          </tr>
        </xsl:for-each-group>
      </tbody>
    </table>
  </xsl:template>
  
</xsl:stylesheet>
When I run that stylesheet with Saxon 9.3 against your sample input I get
Code:
<table>
   <thead>
      <tr>
         <th>Date</th>
         <th>Name</th>
         <th>FathersName</th>
         <th>Occupation</th>
         <th>Result1</th>
         <th>Result2</th>
         <th>Address</th>
         <th>Result3</th>
      </tr>
   </thead>
   <tbody>
      <tr>
         <td>10/12/2010</td>
         <td>A1</td>
         <td>A</td>
         <td>Engineer</td>
         <td>0.1</td>
         <td>0.4</td>
         <td>xxx</td>
         <td>0.5</td>
      </tr>
      <tr>
         <td>10/15/2010</td>
         <td>A2</td>
         <td>A2 Father</td>
         <td>Sales Professional</td>
         <td>-</td>
         <td>-</td>
         <td>A2 Address</td>
         <td>-</td>
      </tr>
      <tr>
         <td>10/17/2010</td>
         <td>-</td>
         <td>-</td>
         <td>-</td>
         <td>0.1</td>
         <td>0.4</td>
         <td>-</td>
         <td>0.6</td>
      </tr>
      <tr>
         <td>10/19/2010</td>
         <td>-</td>
         <td>-</td>
         <td>-</td>
         <td>0.008</td>
         <td>0.005</td>
         <td>-</td>
         <td>0.006</td>
      </tr>
   </tbody>
</table>
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
 
Old July 11th, 2011, 11:02 AM
Authorized User
 
Join Date: Jan 2010
Posts: 32
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Hi Martin,

Thank you for the reply. However, I cannot use XSLT 2. Is there any way we can achieve this in XSLT 1.0?

Thanks





Quote:
Originally Posted by Martin Honnen View Post
Here is an XSLT 2.0 solution not using keys but rather for-each-group:
Code:
<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xs"
  version="2.0">
  
  <xsl:output method="html" indent="yes"/>
  <xsl:strip-space elements="*"/>
    
  <xsl:param name="cols" 
    select="'Date', 'Name', 'FathersName', 'Occupation', 'Result1', 'Result2', 'Address', 'Result3'"/>
  
  <xsl:param name="url2" select="'test2011071102.xml'"/>
  <xsl:variable name="doc2" select="document($url2)"/>
  
  <xsl:template match="Items">
    <table>
      <thead>
        <tr>
          <xsl:for-each select="$cols">
            <th>
              <xsl:value-of select="."/>
            </th>
          </xsl:for-each>
        </tr>
      </thead>
      <tbody>
        <xsl:for-each-group select="Item, $doc2/Items/Item" group-by="normalize-space(Date)">
          <tr>
            <xsl:for-each select="$cols">
              <td>
                <xsl:value-of select="normalize-space((current-group()/*[local-name() eq current()], '-')[1])"/>
              </td>
            </xsl:for-each>
          </tr>
        </xsl:for-each-group>
      </tbody>
    </table>
  </xsl:template>
  
</xsl:stylesheet>
When I run that stylesheet with Saxon 9.3 against your sample input I get
Code:
<table>
   <thead>
      <tr>
         <th>Date</th>
         <th>Name</th>
         <th>FathersName</th>
         <th>Occupation</th>
         <th>Result1</th>
         <th>Result2</th>
         <th>Address</th>
         <th>Result3</th>
      </tr>
   </thead>
   <tbody>
      <tr>
         <td>10/12/2010</td>
         <td>A1</td>
         <td>A</td>
         <td>Engineer</td>
         <td>0.1</td>
         <td>0.4</td>
         <td>xxx</td>
         <td>0.5</td>
      </tr>
      <tr>
         <td>10/15/2010</td>
         <td>A2</td>
         <td>A2 Father</td>
         <td>Sales Professional</td>
         <td>-</td>
         <td>-</td>
         <td>A2 Address</td>
         <td>-</td>
      </tr>
      <tr>
         <td>10/17/2010</td>
         <td>-</td>
         <td>-</td>
         <td>-</td>
         <td>0.1</td>
         <td>0.4</td>
         <td>-</td>
         <td>0.6</td>
      </tr>
      <tr>
         <td>10/19/2010</td>
         <td>-</td>
         <td>-</td>
         <td>-</td>
         <td>0.008</td>
         <td>0.005</td>
         <td>-</td>
         <td>0.006</td>
      </tr>
   </tbody>
</table>
 
Old July 12th, 2011, 06:25 AM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

Here is an XSLT 1.0 stylesheet:
Code:
<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:exsl="http://exslt.org/common"
  xmlns:data="http://example.com/data"
  exclude-result-prefixes="exsl data"
  version="1.0">
  
  <xsl:output method="html" indent="yes"/>
  <xsl:strip-space elements="*"/>
  
  <xsl:key name="item-by-date" match="Item" use="normalize-space(Date)"/>
    
  <data:order xmlns="">
    <Date/>
    <Name/>
    <FathersName/>
    <Occupation/>
    <Result1/>
    <Result2/>
    <Address/>
    <Result3/>
  </data:order>
  
  <xsl:variable name="cols" 
    select="document('')/xsl:stylesheet/data:order/*"/>
  
  <xsl:param name="url2" select="'test2011071102.xml'"/>
  <xsl:variable name="doc2" select="document($url2)"/>
  
  <xsl:template match="Items">
    <table>
      <thead>
        <tr>
          <xsl:for-each select="$cols">
            <th>
              <xsl:value-of select="local-name()"/>
            </th>
          </xsl:for-each>
        </tr>
      </thead>
      <tbody>
        <xsl:variable name="merged-items">
          <xsl:copy-of select="Item | $doc2/Items/Item"/>
        </xsl:variable>
        <xsl:for-each select="exsl:node-set($merged-items)/Item[generate-id() = generate-id(key('item-by-date', normalize-space(Date))[1])]">
          <tr>
            <xsl:variable name="current-group" select="key('item-by-date', normalize-space(Date))"/>
            <xsl:for-each select="$cols">
              <xsl:variable name="element" select="$current-group/*[local-name() = local-name(current())]"/>
              <td>
                <xsl:choose>
                  <xsl:when test="$element">
                    <xsl:value-of select="normalize-space($element)"/>
                  </xsl:when>
                  <xsl:otherwise>-</xsl:otherwise>
                </xsl:choose>
              </td>
            </xsl:for-each>
          </tr>
        </xsl:for-each>
      </tbody>
    </table>
  </xsl:template>
  
</xsl:stylesheet>
It uses exsl:node-set however or you need to use a similar extension function in case the XSLT 1.0 processor does not support exsl:node-set.
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog





Similar Threads
Thread Thread Starter Forum Replies Last Post
Using Function Keys MAKO C# 1 September 8th, 2006 12:17 PM
hot keys in C++ [email protected] C++ Programming 3 January 5th, 2006 02:28 AM
When to define primary keys and foregin keys? method SQL Server 2000 1 August 26th, 2005 09:14 AM
Registry Keys reyboy General .NET 2 March 21st, 2005 08:25 PM
Shortcut keys DARSIN General .NET 1 November 22nd, 2004 10:29 AM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.