Grouping problem

M

Mike King

I don't know how to group the following data in the way I want it. I want
the output of the transformation to be "5678". Does anyone know what I am
doing worry?

<?xml version="1.0"?>
<data>
<unit sn="5">
<test-a>
<result id="0">5</result>
</test-a>
<test-a>
<result id="1">6</result>
</test-a>
<test-b>
<result id="0">10</result>
</test-b>
</unit>
<unit sn="6">
<test-a>
<result id="1">8</result>
</test-a>
<test-a>
<result id="0">7</result>
</test-a>
<test-b>
<result id="0">11</result>
</test-b>
</unit>
</data>


<?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:eek:utput method="text" />

<xsl:template match="unit[1]">
<xsl:apply-templates select="test-a" />
</xsl:template>

<xsl:template match="unit">
<xsl:variable name="my-sort">
<xsl:for-each select="/data/unit[1]/test-a/result">
<xsl:value-of select="@id" />
</xsl:for-each>
</xsl:variable>

<xsl:apply-templates select="test-a">
<xsl:sort
select="count(msxsl:node-set($my-sort)/*[string()=string(current()/result/@id)]/preceding-sibling::*)"
data-type="number" />
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
 
D

David Carlisle

I don't know how to group the following data in the way I want it. I want
the output of the transformation to be "5678". Does anyone know what I am
doing worry?

I couldn't guess what grouping you were trying to do from your required
output, so I can't suggest what xslt you need. You may want to look at
http://www.jenitennison.com/xslt/grouping
However I can point out some errors in your code

<xsl:variable name="my-sort">
<xsl:for-each select="/data/unit[1]/test-a/result">
<xsl:value-of select="@id" />
</xsl:for-each>

This result tree fragment variable just consists of a single root node
(/) with child a text node with value which is the concatenation of all
the selected id attribute values. There are no elements.

so when you make this into a node set

msxsl:node-set($my-sort)

You get a single root node equivalent to the root node of a document
with no elements so msxsl:node-set($my-sort)/* will always be the empty
node set.

David
 
M

Mike King

I couldn't guess what grouping you were trying to do from your required
output, so I can't suggest what xslt you need. You may want to look at
http://www.jenitennison.com/xslt/grouping
However I can point out some errors in your code

<xsl:variable name="my-sort">
<xsl:for-each select="/data/unit[1]/test-a/result">
<xsl:value-of select="@id" />
</xsl:for-each>

This result tree fragment variable just consists of a single root node
(/) with child a text node with value which is the concatenation of all
the selected id attribute values. There are no elements.

so when you make this into a node set

msxsl:node-set($my-sort)

You get a single root node equivalent to the root node of a document
with no elements so msxsl:node-set($my-sort)/* will always be the empty
node set.

David

The problem I am having is the test-a elements are unsorted between unit
elements. I don't care how the test-a elements are sorted as long as they
are sorted the same way. So what I have tried to do is repeat the order of
the first unit's test-a elements. I know the first unit will always be at
/data/unit[1] so that's why I did that. The test-a element always has one
result element, so I don't have to worry about concatenation. I was hoping
$my-sort would contain a sequence of text nodes, which would allow me to
order following test-a elements based on the first unit's test-a elements.
 
D

David Carlisle

...
The test-a element always has one
result element, so I don't have to worry about concatenation.

But you selected more than one such element and concatenated the result.
you get the concatenation of all the id values of result elements below
the first unit, so "01" in your sample input.

I was hoping
$my-sort would contain a sequence of text nodes, which would allow me to
order following test-a elements based on the first unit's test-a elements.

It contains a root node with child a single text node, but even if it
did contain a sequence of text nodes (which is never possible in XPath
1, adjacent text nodes that share a parent atre always merged)
your Xpath of
msxsl:node-set($my-sort)/*[....

would select nothing as msxsl:node-set($my-sort)/* selects al the element
children (and text nodes are not elements).

I think that for each unit you just want to iterate through the first
one and select children with ids in that order. You don't need
xx:node-set for that:


<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"<xsl:eek:utput method="text" />

<xsl:variable name="order" select="data/unit[1]/test-a/result"/>

<xsl:template match="unit">
unit [<xsl:value-of select="@sn"/>]
<xsl:variable name="u" select="."/>
<xsl:for-each select="$order/@id">
<xsl:apply-templates select="$u/test-a/result[@id=current()]"/>
</xsl:for-each>

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


produces

unit [5]
56

unit [6]
78

on your sample input.

David
 
M

Mike King

The following XSLT works for my test case but I don't know why. I would
think the value of the keys needs to be the position of the test-a element
for this to work. How can I assign the position to the keys?


<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:eek:utput method="text" />
<xsl:key name="my-testa-order" match="/data/unit[1]/test-a/result/@id"
use="current()" />

<xsl:template match="unit">
<xsl:apply-templates select="test-a">
<xsl:sort select="key('my-testa-order', result/@id)"
data-type="number" />
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
 
D

David Carlisle

Mike King said:
The following XSLT works for my test case but I don't know why.

It works becaus eon your test file the results in teh first unit have
unique values, that are in the same order as the id's so your sort
values are 5 and 6 (the values of the results). If for example the
values in the first unit had been equal then everything would get that
sort value and no sorting woul happen.

I would
think the value of the keys needs to be the position of the test-a element
for this to work. How can I assign the position to the keys?


You can't: keys always return nodes not arbitrary values (such as integer
positions)

You could use a sort of
<xsl:sort select="count(key('my-testa-order', result/@id)/../../preceding-sibling::test-a)"
but see previous reply

David
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:eek:utput method="text" />
<xsl:key name="my-testa-order" match="/data/unit[1]/test-a/result/@id"
use="current()" />

<xsl:template match="unit">
<xsl:apply-templates select="test-a">
<xsl:sort select="key('my-testa-order', result/@id)"
data-type="number" />
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,994
Messages
2,570,222
Members
46,810
Latest member
Kassie0918

Latest Threads

Top