Eliminating duplicate information in selected sorted rows

M

Matt B

Can somebody help me with this please...

I have an xml file along the lines of

<results>
<result status="Pass">
<person name="Fred"/>
<subject name="English" />
</result>
<result status="Pass">
<person name="Harry"/>
<subject name="Maths" />
</result>
<result status="Fail">
<person name="Fred"/>
<subject name="History" />
</result>
<result status="Fail">
<person name="Harry"/>
<subject name="English" />
</result>
<result status="Pass">
<person name="Fred"/>
<subject name="Maths" />
</result>
<result status="Pass">
<person name="Harry"/>
<subject name="History" />
</result>
</results>

And need to generate html for all result staus="Passes" sorted and displayed
like this:

Passes:
Name Subject
------ --------
Fred English
- Maths
Harry History
- Maths

My best attempt so far is:

....
<xsl:for-each select="results/result[@status='Pass']">
<xsl:sort select="person/@name"/>
<tr>
<td>
<xsl:value-of select="person/@name"/>
<xsl:value-of select="subject/@name"/>
</td>
</tr>
</xsl:for-each>
....

Which gives:

Passes:
Name Subject
------ --------
Fred English
Fred Maths
Harry History
Harry Maths

The problems as I see it are that the output is a sub-set af the whole data,
and it is sorted.

Any ideas on how to remove the duplicate entries in the first column would
be very welcome.
 
I

Ixa

<xsl:sort select="person/@name"/>
<tr>
<td>
<xsl:value-of select="person/@name"/>
<xsl:value-of select="subject/@name"/>
</td>
</tr>
</xsl:for-each> [...]
Any ideas on how to remove the duplicate entries in the first column
would be very welcome.

One suggestion:

---8<---8<---
<xsl:variable name="name" select="person/@name"/>
<xsl:if test="not(preceding::person[@name = $name])">
<xsl:value-of select="person/@name"/>
</xsl:if>
---8<---8<---
 
M

Matt B

Ixa said:
<xsl:for-each select="results/result[@status='Pass']">
<xsl:sort select="person/@name"/>
<tr>
<td>
<xsl:value-of select="person/@name"/>
<xsl:value-of select="subject/@name"/>
</td>
</tr>
</xsl:for-each> [...]
Any ideas on how to remove the duplicate entries in the first column
would be very welcome.

One suggestion:

---8<---8<---
<xsl:variable name="name" select="person/@name"/>
<xsl:if test="not(preceding::person[@name = $name])">
<xsl:value-of select="person/@name"/>
</xsl:if>
---8<---8<---

Thanks for the suggestion. I tried it but got blanks for *every* line.
 
I

Ixa

Thanks for the suggestion. I tried it but got blanks for *every* line.

Hmm, I get the expected result. Here's the script that I used:

---8<---8<---
<xsl:for-each select="results/result[@status='Pass']">
<xsl:sort select="person/@name"/>
<tr>
<td>
<xsl:variable name="name" select="person/@name"/>
<xsl:if test="not(preceding::person[@name = $name])">
<xsl:value-of select="person/@name"/>
</xsl:if>
</td>
<td>
<xsl:value-of select="subject/@name"/>
</td>
</tr>
</xsl:for-each>
---8<---8<---

and the result (name once in first column and all passed items in
second column):

---8<---8<---
<tr>
<td>Fred</td>
<td>English</td>
</tr>
<tr>
<td></td>
<td>Maths</td>
</tr>
<tr>
<td>Harry</td>
<td>Maths</td>
</tr>
<tr>
<td></td>
<td>History</td>
</tr>
---8<---8<---
 
M

Matt B

Ixa said:
Hmm, I get the expected result. Here's the script that I used:
....
I tried again, and got these results - the script is after (sorry for the
length)...


With all the data in place:
Dick Geography
Dick History
Harry English
Harry French
Harry Maths
Tom English
Tom Maths


Processing person names:
Geography
History
English
French
Harry Maths
English
Tom Maths


xml:

<?xml version="1.0" encoding="iso-8859-1"?>
<?xml-stylesheet type="text/xsl" href="report.xsl"?>
<report>
<results>
<result status="Pass">
<subject name="Maths"/>
<person name="Tom" />
</result>
<result status="Fail">
<subject name="Maths"/>
<person name="Dick" />
</result>
<result status="Pass">
<subject name="Maths"/>
<person name="Harry" />
</result>
<result status="Fail">
<subject name="History"/>
<person name="Tom" />
</result>
<result status="Pass">
<subject name="History"/>
<person name="Dick" />
</result>
<result status="Fail">
<subject name="History"/>
<person name="Harry" />
</result>
<result status="Pass">
<subject name="English"/>
<person name="Tom" />
</result>
<result status="Fail">
<subject name="English"/>
<person name="Dick" />
</result>
<result status="Pass">
<subject name="English"/>
<person name="Harry" />
</result>
<result status="Fail">
<subject name="Geography"/>
<person name="Tom" />
</result>
<result status="Pass">
<subject name="Geography"/>
<person name="Dick" />
</result>
<result status="Fail">
<subject name="Geography"/>
<person name="Harry" />
</result>
<result status="Pass">
<subject name="French"/>
<person name="Harry" />
</result>
</results>
</report>

xsl:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/report">
<html>
<body>
<table border="1">
<xsl:for-each select="results/result[@status='Pass']">
<xsl:sort select="person/@name"/>
<xsl:sort select="subject/@name"/>
<tr>
<td>
<xsl:value-of select="person/@name"/>
</td>
<td>
<xsl:value-of select="subject/@name"/>
</td>
</tr>
</xsl:for-each>
</table>
<table border="1">
<xsl:for-each select="results/result[@status='Pass']">
<xsl:sort select="person/@name"/>
<xsl:sort select="subject/@name"/>
<tr>
<td>
<xsl:variable name="name" select="person/@name"/>
<xsl:if test="not(preceding::person[@name = $name])">
<xsl:value-of select="person/@name"/>
</xsl:if> 
</td>
<td>
<xsl:value-of select="subject/@name"/>
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
 
I

Ixa

I tried again, and got these results - the script is after

So the sorting confuses the tests and another approach might be better.
Here's one (search for unique persons and their successful results, not
vice versa):

---8<---8<---
<table border="1">
<xsl:for-each select="//person/@name">
<xsl:sort/>
<xsl:variable name="name" select="."/>
<xsl:variable name="items"
select="/report/results/result[person[@name = $name] and
@status='Pass']"/>
<xsl:if test="not(preceding::person[@name = $name])">
<tr>
<td>
<xsl:value-of select="."/>
</td>
<td>
<xsl:for-each select="$items">
<xsl:sort select="subject/@name"/>
<xsl:if test="position() = 1">
<xsl:value-of select="subject/@name"/>
</xsl:if>
</xsl:for-each>
</td>
</tr>
<xsl:for-each select="$items">
<xsl:sort select="subject/@name"/>
<xsl:if test="position() &gt; 1">
<tr>
<td/>
<td>
<xsl:value-of select="subject/@name"/>
</td>
</tr>
</xsl:if>
</xsl:for-each>
</xsl:if>
</xsl:for-each>
</table>
---8<---8<---
 
M

Matt B

Ixa said:
So the sorting confuses the tests and another approach might be better.
Here's one (search for unique persons and their successful results, not
vice versa):

Lateral thinking - I love it! It works great!

Thanks for your trouble :)
 

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,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top