Forum Moderators: open

Message Too Old, No Replies

XSLT - Grouping indirectly referenced elements

I'm melting!

         

john_k

10:48 pm on Oct 28, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I have been fighting with this for the better part of the day and would greatly appreciate hearing any ideas to help me along.

I am doing an XSLT transformation on some XML provided by a webservice. A stripped down version of the XML is pasted at the end of this post. I need to group the information in the DACase/Charge nodes under the ReferralAgency. So an example of the output is:


XYZ Police Dept
---------------
A B
abcd 123
efgh 456
ijkl 789
mnop 012


ABC County Sheriff
------------------
A B
grst 345

Some constraints about the data:
- The Charge element will always contain an IncidentId element
- The Charge/IncidentId value will always exist in one and only one of the Referral/Incident/IncidentId elements
- A Referral element does not always have an Incident element
- A Referral/Incident/IncidentId element can be present with no corresponding Charge/IncidentId element

By using a Key, I can select the Referral nodes by ReferralAgency.
<xsl:key name="referrals-by-agency" match="Referral" use="ReferralAgency" />

For the life of me, however, I cannot figure out a way to traverse the Charge nodes to get the desired output. I thought I had it, but I keep running into the prospect of having column headings on an empty table (which is bad) when there is a Referral without any corresponding Charge (like ReferralId=400 in the XML below).

Is there any way to get the desired output and also avoid any empty tables? Any ideas?

If I had my druthers, the Charge nodes would be appearing under the Incident nodes in the XML. But I don't have them :(

Oh yeah - if it matters, the transformation is being done on the server in .Net.

Thanks for any help!

XML Data follows (I have stripped out everything not pertinent to my question)
-----------


<?xml version="1.0" encoding="utf-8"?>
<DACase>
<DACaseId>10</DACaseId>
<Referral>
<ReferralId>100</ReferralId>
<ReferralAgency>XYZ Police Dept</ReferralAgency>
<Incident>
<IncidentId>1000</IncidentId>
</Incident>
</Referral>
<Referral>
<ReferralId>200</ReferralId>
<ReferralAgency>XYZ Police Dept</ReferralAgency>
<Incident>
<IncidentId>2000</IncidentId>
</Incident>
</Referral>
<Referral>
<ReferralId>300</ReferralId>
<ReferralAgency>ABC County Sheriff</ReferralAgency>
<Incident>
<IncidentId>3000</IncidentId>
</Incident>
</Referral>
<Referral>
<ReferralId>400</ReferralId>
<ReferralAgency>Wazoo PD</ReferralAgency>
</Referral>
<Charge>
<ChargeId>10000</ChargeId>
<IncidentId>1000</IncidentId>
<ElementA>abcd</ElementA>
<ElementB>123</ElementB>
</Charge>
<Charge>
<ChargeId>20000</ChargeId>
<IncidentId>1000</IncidentId>
<ElementA>efgh</ElementA>
<ElementB>456</ElementB>
</Charge>
<Charge>
<ChargeId>30000</ChargeId>
<IncidentId>2000</IncidentId>
<ElementA>ijkl</ElementA>
<ElementB>789</ElementB>
</Charge>
<Charge>
<ChargeId>40000</ChargeId>
<IncidentId>2000</IncidentId>
<ElementA>mnop</ElementA>
<ElementB>012</ElementB>
</Charge>
<Charge>
<ChargeId>50000</ChargeId>
<IncidentId>3000</IncidentId>
<ElementA>qrst</ElementA>
<ElementB>345</ElementB>
</Charge>
</DACase>

johnl

1:11 pm on Nov 2, 2005 (gmt 0)

10+ Year Member



hi,
if you are not molten yet and have found a solution, i would be interested in seeing it.

Otherwise you might try:


<?xml version="1.0" encoding="iso8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html"/>

<xsl:key name="rags" match="//Referral" use="ReferralAgency"/>
<xsl:template match="/">
<html>
<body>
<xsl:for-each select="//Referral[count(. ¦ key('rags', ReferralAgency)[1]) = 1]">
<xsl:if test="ReferralAgency/../Incident/IncidentId = not('')">
<table border="1" bordercolor="#889977">
<tr><td><xsl:value-of select="ReferralAgency" /></td><td>ElementA</td><td>ElementB</td></tr>
<xsl:for-each select="key('rags', ReferralAgency)">
<xsl:variable name="ra" select="."/>

<xsl:for-each select="ReferralAgency/../Incident/IncidentId">
<xsl:if test=". = not('')">
<xsl:variable name="riid" select="."/>
<xsl:for-each select="//Charge/IncidentId">
<xsl:if test=". = $riid">
<tr>
<td><xsl:value-of select="." /></td>
<td><xsl:value-of select="../ElementA" /></td>
<td><xsl:value-of select="../ElementB" /></td>
</tr>
</xsl:if>
</xsl:for-each>

</xsl:if>
</xsl:for-each>
</xsl:for-each>
<br />
</table>
</xsl:if>
</xsl:for-each>

</body>
</html>
</xsl:template>

</xsl:stylesheet>

which gives the desired output. You also might search the internet for "+grouping +Muenchian" to read more about the method used.

greetings!

john_k

6:21 pm on Nov 2, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Thanks for the response. I did check into the Muenchian method quite a bit before posting this question. I was unable to get around this combination of possibilities:
- The same ReferralAgency may appear in multiple Referral elements, and the grouping needs to treat them as the same entity. In the sample XML, that means that Charge elements with IncidentId=1000 and IncidentId=2000 are grouped together.
- A Referral element can be present that does not have any Charge elements relating to it. When that occurs, the ReferralAgency should not be listed with the output and no column headings should show up.

I did resolve this. I will have to compare your suggestion to my solution. I'll post back here later (maybe not today though) with the results of that comparison.

cheers!