Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Grouping/Sorting Problem

16 views
Skip to first unread message

Sarah_Lund

unread,
Oct 5, 2006, 9:47:02 AM10/5/06
to
First I need to create a table for each Selection
Then within each table I need to group by each
Configuration_Data/Module/@nID = Performance_Data/Perf_Data/Perf_Module/@nID
Then for each Configuration_Data/Module/@nID =
Performance_Data/Perf_Data/Perf_Module/@nID I need to display Category/@name
and Perf_Category/@name but these must be sorted according to
Category/@displayOrder and Perf_Module/Perf_Category/@displayOrder

So for each Configuration_Data/Module/@nID =
Performance_Data/Perf_Data/Perf_Module/@nID I need to dump all Category and
all Perf_Module/Perf_Category into a set and then sort them all by their
@displayOrder.

And then display them left to right in two columns in the table. The results
would like like the following:
<table>
<tr><td>Selection 1</td></tr>
<tr><td>Base Unit Module</td></tr>
<tr><td>Unit</td><td>Elevation</td></tr>
<tr><td>Unit Roof</td><td>Unit Airflow</td></tr>
<tr><td>Htg</td><td>Frame</td></tr>
<tr><td>Fan Module</td></tr>
...
</table>

I had gotten help to get something like this working in the past but having
trouble applying to this case. Any help is appreciated!
An excerpt from the xml file is below:
<Products>
<Begin_Product nID="2002421">
<Selection>
<Selection_Number>1</Selection_Number>
<Configuration_Data>
<Module displayOrder="10" nID="4656" name="Base Unit Module">
<Category displayOrder="10" nID="21" name="Unit"/>
<Category displayOrder="50" nID="43" name="Frame"/>
<Category displayOrder="20" nID="67" name="Unit Roof"/>
</Module>
<Module displayOrder="20" nID="4658" name="Fan Module">
<Category displayOrder="10" nID="96" name="Fan Module"/>
<Category displayOrder="20" nID="63" name="Fan Size"/>
</Module>
</Configuration_Data>
<Performance_Data>
<Perf_Data>
<Perf_Module nID="4656" name="Base Unit Module">
<Perf_Category displayOrder="30" nID="10" name="Unit Airflow"/>
<Perf_Category displayOrder="10" nID="91" name="Elevation"/>
<Perf_Category displayOrder="40" nID="13" name="Htg"/>
</Perf_Module>
<Perf_Module nID="4658" name="Fan Module">
<Perf_Category displayOrder="20" nID="23" name="Airflow"/>
<Perf_Category displayOrder="90" nID="30" name="AbsPower"/>
</Perf_Module>
</Perf_Data>
</Performance_Data>
</Selection>
</Begin_Product>
</Products>

Michelle Carlson

unread,
Oct 6, 2006, 12:19:11 PM10/6/06
to
Sarah,
Explore using the XSLT processor's nodeset function or use XSLT 2.0.
I don't think you can do what you need to using a single transform and
XSLT 1.0 without using processor extension functions.
I was able to get the information grouped and sorted, but can't
reference that nodeset in XSLT 1.0 to display the values in tabular
columns without using the nodeset extension function specific to my
XSLT processor. To avoid processor extensions and use XSLT 1.0, you'd
need to do multiple transformations.
1. XML to XML transform to group and sort the nodes; your result
transform might look something like this:

<Data>
<Module displayOrder="10" nID="4656" name="Base Unit Module">
<Category displayOrder="10" nID="21" name="Unit"/>
<Perf_Category displayOrder="10" nID="91" name="Elevation"/>
<Category displayOrder="20" nID="67" name="Unit Roof"/>
<Perf_Category displayOrder="30" nID="10" name="Unit Airflow"/>
<Perf_Category displayOrder="40" nID="13" name="Htg"/>
<Category displayOrder="50" nID="43" name="Frame"/>
</Module>
<Module displayOrder="20" nID="4658" name="Fan Module">
<Category displayOrder="10" nID="96" name="Fan Module"/>
<Category displayOrder="20" nID="63" name="Fan Size"/>
<Perf_Category displayOrder="20" nID="23" name="Airflow"/>
<Perf_Category displayOrder="90" nID="30" name="AbsPower"/>
</Module>
</Data>
</Selection>
2. XML to HTML transform to generate the table using position of nodes
to determine whether they are in the first or second column.

Sarah_Lund

unread,
Oct 6, 2006, 3:07:01 PM10/6/06
to
Michelle, Thank you for your reply. I have been using the nodeset function
and do come close but of course not just right. Is it possible to use one xsl
file to generate an xml file and then also process the newly created xml file
into HTML display?
Thank you,
Sarah

Dimitre Novatchev

unread,
Oct 6, 2006, 11:22:39 PM10/6/06
to
The following transformation produces the desired result -- without any
intermediate RTFs and the need to convert them to regular trees:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/">
<html>
<xsl:apply-templates/>
</html>
</xsl:template>

<xsl:template match="Selection_Number">
<table>
<tr><td>Selection <xsl:value-of select="."/></td></tr>
<xsl:for-each select="../Configuration_Data/Module">
<xsl:sort select="@displayOrder" data-type="number"/>
<xsl:variable name="vpMod" select=
"../../Performance_Data/Perf_Data/Perf_Module
[@nID = current()/@nID]
"/>
<tr>
<td><xsl:value-of select="@name"/></td>
</tr>
<xsl:for-each select="Category">
<xsl:sort select="@displayOrder" data-type="number"/>
<xsl:variable name="vPos" select="position()"/>
<tr>
<td>
<xsl:value-of select="@name"/>
</td>
<td>
<xsl:for-each select="$vpMod/Perf_Category">
<xsl:sort select="@displayOrder" data-type="number"/>
<xsl:if test="position() = $vPos">
<xsl:value-of select="@name"/>
</xsl:if>
</xsl:for-each>
</td>
</tr>

</xsl:for-each>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>

Cheers,
Dimitre Novatchev

"Sarah_Lund" <Sara...@discussions.microsoft.com> wrote in message
news:570EFAE9-042E-44D0...@microsoft.com...

Sarah_Lund

unread,
Oct 9, 2006, 9:49:01 PM10/9/06
to
Thank you, that gets me partially there but the way you suggest doesn't put
the results in the 2 columns in order. Do you see how I could modify the
following to get the data in two columns?
<xsl:for-each select="/Products/Begin_Product/Selection">
<xsl:for-each select="Configuration_Data/Module">

<xsl:variable name="vpMod" select
="//Products/Begin_Product/Selection/Performance_Data/Perf_Data/Perf_Module[@nID = current()/@nID]"/>

<br><b><xsl:value-of select="@name"/></b></br>
<xsl:for-each select="msxsl:node-set(Category|$vpMod//Perf_Category)">

<xsl:sort select="@displayOrder" data-type="number"/>
<br><xsl:value-of select="@name"/> - <xsl:value-of
select="@displayOrder"/></br>

</xsl:for-each>
</xsl:for-each>
</xsl:for-each>

Dimitre Novatchev

unread,
Oct 9, 2006, 11:43:33 PM10/9/06
to
Dear Sarah,

I have checked and re-checked that the transformation provided in my last
message, when applied on the exact source xml document in your original
message produces the exact wanted results as specified in your original
message.

It seems that now you have other, yet not described problems -- please,
describe them in detail that will allow them to be understood -- preferrably
in a separate message.

Do understand that the ability of anybody to solve a problem directly
depends on how well (clearly, compactly, unambiguously, etc. ...) this
problem is presented.


Cheers,
Dimitre Novatchev

"Sarah_Lund" <Sara...@discussions.microsoft.com> wrote in message

news:AB8EC82E-27F9-4A2E...@microsoft.com...

Sarah_Lund

unread,
Oct 10, 2006, 4:41:01 PM10/10/06
to
Dimitre,
Your transformation results in the following:

<table>
<tr>
<td>Selection 1</td>
</tr>
<tr>
<td>Base Unit Module</td>
</tr>
<tr>
<td>Unit</td>
<td>Elevation</td>
</tr>
<tr>
<td>Unit Roof</td>
<td>Unit Airflow</td>
</tr>
<tr>
<td>Frame</td>
<td>Htg</td>

</tr>
<tr>
<td>Fan Module</td>
</tr>
<tr>
<td>Fan Module</td>
<td>Airflow</td>
</tr>
<tr>
<td>Fan Size</td>
<td>AbsPower</td>
</tr>
</table>


Notice above in the 5th row the first <td> contains 'Frame' and the second
<td> has 'Htg' but it should be the reverse because the displayOrder value
for 'Htg' is 40 and the displayOrder value for 'Frame' is 50.

What it looks like to me is that all the values from
/Products/Begin_Product/Selection/Configuration_Data/Module/Category/@name
are put in the first <td> of each row and all the values from
/Products/Begin_Product/Selection/Performance_Data/Perf_Data/Perf_Module/Perf_Category/@name are put in the second <td> of each row.

But what needs to happen is for each Selection and for each
Configuration_Data/Module=Performance_Data/Perf_Data/Perf_Module, SORT using
@displayOrder and write the @name value left to right in two columns in a
table.

The following gives me the correctly grouped and sorted results but in a
single column. I need help to get it into two columns. I have tried using
POSITION and COUNT functions but can't get it to work.
<?xml version="1.0"?>


<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

xmlns:msxsl="urn:schemas-microsoft-com:xslt">


<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/">
<html>
<xsl:apply-templates/>
</html>
</xsl:template>

<xsl:template match="/">

<xsl:for-each select="/Products/Begin_Product/Selection">
<xsl:for-each select="Configuration_Data/Module">

<xsl:variable name="vpMod" select
="//Products/Begin_Product/Selection/Performance_Data/Perf_Data/Perf_Module[@nID
= current()/@nID]"/>

<br><b><xsl:value-of select="@name"/></b></br>
<xsl:for-each select="msxsl:node-set(Category|$vpMod//Perf_Category)">

<xsl:sort select="@displayOrder" data-type="number"/>
<br><xsl:value-of select="@name"/> - <xsl:value-of
select="@displayOrder"/></br>

</xsl:for-each>
</xsl:for-each>
</xsl:for-each>

</xsl:template>
</xsl:stylesheet>

The xml is below in the event you don't have it from before.

I hope I have explained this clearly. Thank you for all your help. Regards,
Sarah

Dimitre Novatchev

unread,
Oct 10, 2006, 11:47:54 PM10/10/06
to
> Notice above in the 5th row the first <td> contains 'Frame' and the second
> <td> has 'Htg' but it should be the reverse because the displayOrder value
> for 'Htg' is 40 and the displayOrder value for 'Frame' is 50.
>

This is what I could understand was wanted -- from your original post.

> What it looks like to me is that all the values from
> /Products/Begin_Product/Selection/Configuration_Data/Module/Category/@name
> are put in the first <td> of each row and all the values from
> /Products/Begin_Product/Selection/Performance_Data/Perf_Data/Perf_Module/Perf_Category/@name
> are put in the second <td> > of each row.
>
> But what needs to happen is for each Selection and for each
> Configuration_Data/Module=Performance_Data/Perf_Data/Perf_Module, SORT
> using
> @displayOrder and write the @name value left to right in two columns in a
> table.

Not quite clear.

Could you, please, try to provide a compact, unambiguous and understandable
description of the problem?

(for example, it would be very useful to get rid of all the html markup and
just explain the properties of the elements (cells and rows) of the table
and how they are related to the source xml document.

Inability to do so may usually mean that the problem is not yet well
undestood or even that the problem is incorrectly understood.


Cheers,
Dimitre Novatchev.

"Sarah_Lund" <Sara...@discussions.microsoft.com> wrote in message

news:E071BAC1-BA41-4B2C...@microsoft.com...

Sarah_Lund

unread,
Oct 11, 2006, 5:07:02 PM10/11/06
to
Thank you for your understanding and I will try to clarify.

I need to create a table For Each Selection in the xml file.
Then in each table For Each
Configuration_Data/Module/@nID=Performance_Data/Perf_Data/Perf_Module/@nID, I
need to SORT on
/Products/Begin_Product/Selection/Configuration_Data/Module/Category/@displayOrder
and
/Products/Begin_Product/Selection/Performance_Data/Perf_Data/Perf_Module/Perf_Category/@displayOrder
(together as one list). And then put the
/Products/Begin_Product/Selection/Configuration_Data/Module/Category/@name
and
/Products/Begin_Product/Selection/Performance_Data/Perf_Data/Perf_Module/Perf_Category/@name
values in order horizontally in multiple columns with each item in an
individual table cell.

Thank you in advance for trying to understand my explanation.
Sarah

The xml is below in the event you don't have it from before.
<Products>
<Begin_Product nID="2002421">
<Selection>
<Selection_Number>1</Selection_Number>
<Configuration_Data>
<Module displayOrder="10" nID="4656" name="Base Unit Module">
<Category displayOrder="10" nID="21" name="Unit"/>
<Category displayOrder="50" nID="43" name="Frame"/>
<Category displayOrder="20" nID="67" name="Unit Roof"/>
</Module>
<Module displayOrder="20" nID="4658" name="Fan Module">
<Category displayOrder="10" nID="96" name="Fan Module"/>
<Category displayOrder="20" nID="63" name="Fan Size"/>
</Module>
</Configuration_Data>
<Performance_Data>
<Perf_Data>
<Perf_Module nID="4656" name="Base Unit Module">
<Perf_Category displayOrder="30" nID="10" name="Unit Airflow"/>
<Perf_Category displayOrder="10" nID="91" name="Elevation"/>
<Perf_Category displayOrder="40" nID="13" name="Htg"/>
</Perf_Module>

</Perf_Module nID="4658" name="Fan Module">

Dimitre Novatchev

unread,
Oct 11, 2006, 9:49:04 PM10/11/06
to
This is a wellknown problem and it has a wellknown solution.

As Michelle has explained, it is trivial to solve, given one can use the
xxx:node-set() extension function.

I assume that you do not want to use any extension functions.

In this case, here's one solution:

This XSLT transformation:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="kModByID" match="Module | Perf_Module"
use="@nID"/>

<xsl:template match="/">
<html>

<xsl:for-each select=
"/*/*/*/*/Module
[generate-id()
=
generate-id(key('kModByID',@nID)[1])
]"
>
<table>
<xsl:for-each select=
"(
/*/*/*/*/Module
|
/*/*/*/*/*/Perf_Module
)
[@nID = current()/@nID] /*


">
<xsl:sort select="@displayOrder" data-type="number"/>

<xsl:variable name="vID" select="../@nID"/>

<xsl:if test="position() mod 2 = 1">
<tr>
<td><xsl:value-of select="@name"/></td>
<td>
<xsl:call-template name="sortedNth">
<xsl:with-param name="pId" select="$vID"/>
<xsl:with-param name="pPos"
select="position()+1"/>
</xsl:call-template>
</td>
</tr>
</xsl:if>

</xsl:for-each>
</table>
</xsl:for-each>
</html>
</xsl:template>

<xsl:template name="sortedNth">
<xsl:param name="pId" select="0"/>
<xsl:param name="pPos" select="0"/>

<xsl:if test="$pPos > 0 and $pId > 0">
<xsl:for-each select=
"/*/*/*/*/*[@nID = $pId]/Category
|
/*/*/*/*/*/*[@nID = $pId]/Perf_Category


"
>
<xsl:sort select="@displayOrder" data-type="number"/>

<xsl:if test="position() = $pPos">
<xsl:copy-of select="string(@name)"/>
</xsl:if>
</xsl:for-each>
</xsl:if>

</xsl:template>
</xsl:stylesheet>


when applied on the origianl source xml document:

<Products>
<Begin_Product nID="2002421">
<Selection>
<Selection_Number>1</Selection_Number>
<Configuration_Data>
<Module displayOrder="10" nID="4656" name="Base Unit Module">
<Category displayOrder="10" nID="21" name="Unit"/>
<Category displayOrder="50" nID="43" name="Frame"/>
<Category displayOrder="20" nID="67" name="Unit Roof"/>
</Module>
<Module displayOrder="20" nID="4658" name="Fan Module">
<Category displayOrder="10" nID="96" name="Fan Module"/>
<Category displayOrder="20" nID="63" name="Fan Size"/>
</Module>
</Configuration_Data>
<Performance_Data>
<Perf_Data>
<Perf_Module nID="4656" name="Base Unit Module">
<Perf_Category displayOrder="30" nID="10" name="Unit Airflow"/>
<Perf_Category displayOrder="10" nID="91" name="Elevation"/>
<Perf_Category displayOrder="40" nID="13" name="Htg"/>
</Perf_Module>

<Perf_Module nID="4658" name="Fan Module">
<Perf_Category displayOrder="20" nID="23" name="Airflow"/>
<Perf_Category displayOrder="90" nID="30" name="AbsPower"/>
</Perf_Module>
</Perf_Data>
</Performance_Data>
</Selection>
</Begin_Product>
</Products>

produces the wanted result:

<html>
<table>


<tr>
<td>Unit</td>
<td>Elevation</td>
</tr>
<tr>
<td>Unit Roof</td>
<td>Unit Airflow</td>
</tr>
<tr>

<td>Htg</td>
<td>Frame</td>
</tr>

</table>
<table>


<tr>
<td>Fan Module</td>

<td>Fan Size</td>
</tr>
<tr>
<td>Airflow</td>


<td>AbsPower</td>
</tr>
</table>

</html>

Cheers,
Dimitre Novatchev

"Sarah_Lund" <Sara...@discussions.microsoft.com> wrote in message

news:2FB78E50-070F-4ADA...@microsoft.com...

Michelle Carlson

unread,
Oct 12, 2006, 10:23:07 AM10/12/06
to
Excellent solution Dimitre!

Sarah_Lund

unread,
Oct 12, 2006, 4:50:02 PM10/12/06
to
Thank you so much - this gets me well on my way!

Sarah

0 new messages