Title: XSL1.0 excluding previous nodes
Tags: xslt-1.0
Question: I'm constrained to vanilla XSLT1.0 (no extensions) and MSXML transforms

Completely stumped on a problem. 

I have an XML that I need to create HTML output from. Nodes need to be sorted by version_code then by despatch_tape_colour, BUT then grouped by address_line_1 (easier to look at image below to see: cream colored headings are group headers)

```<order&gt;
   <order_no&gt;16292</order_no&gt;
   <job_no&gt;16292</job_no&gt;
   <loads&gt;
      <LoadID&gt;10</LoadID&gt;
      <load_seq&gt;10</load_seq&gt;
      <load_address_1&gt;731 Fraser Street</load_address_1&gt;
      <load_haulier&gt;Purolator</load_haulier&gt;
      <load_splits&gt;
         <load_split_id&gt;10</load_split_id&gt;
         <load_split_description&gt;Prince Rupert Northern View</load_split_description&gt;
         <version_code&gt;Z1</version_code&gt;
         <despatch_tape_colour&gt;FLAT</despatch_tape_colour&gt;
      </load_splits&gt;
   </loads&gt;
   <loads&gt;
      <LoadID&gt;11</LoadID&gt;
      <load_seq&gt;11</load_seq&gt;
      <load_address_1&gt;8506 Main Street</load_address_1&gt;
      <load_haulier&gt;Purolator</load_haulier&gt;
      <load_splits&gt;
         <load_split_id&gt;11</load_split_id&gt;
         <load_split_description&gt;*</load_split_description&gt;
         <version_code&gt;Z1</version_code&gt;
         <despatch_tape_colour&gt;FLAT</despatch_tape_colour&gt;
      </load_splits&gt;
   </loads&gt;
   <loads&gt;
      <LoadID&gt;19</LoadID&gt;
      <load_seq&gt;19</load_seq&gt;
      <load_address_1&gt;130 - 766 Cliveden Place</load_address_1&gt;
      <load_haulier&gt;Purolator</load_haulier&gt;
      <load_splits&gt;
         <load_split_id&gt;19</load_split_id&gt;
         <load_split_description&gt;*</load_split_description&gt;
         <version_code&gt;Z1</version_code&gt;
         <despatch_tape_colour&gt;FLAT</despatch_tape_colour&gt;
      </load_splits&gt;
   </loads&gt;
   <loads&gt;
      <LoadID&gt;123</LoadID&gt;
      <load_seq&gt;123</load_seq&gt;
      <load_address_1&gt;100 Railway Avenue West</load_address_1&gt;
      <load_haulier&gt;Purolator</load_haulier&gt;
      <load_splits&gt;
         <load_split_id&gt;123</load_split_id&gt;
         <load_split_description&gt;*</load_split_description&gt;
         <version_code&gt;Z2</version_code&gt;
         <despatch_tape_colour&gt;FLAT</despatch_tape_colour&gt;
      </load_splits&gt;
   </loads&gt;
   <loads&gt;
      <LoadID&gt;124</LoadID&gt;
      <load_seq&gt;124</load_seq&gt;
      <load_address_1&gt;130 - 766 Cliveden Place</load_address_1&gt;
      <load_haulier&gt;Purolator</load_haulier&gt;
      <load_splits&gt;
         <load_split_id&gt;124</load_split_id&gt;
         <load_split_description&gt;*</load_split_description&gt;
         <version_code&gt;Z2</version_code&gt;
         <despatch_tape_colour&gt;FLAT</despatch_tape_colour&gt;
      </load_splits&gt;
   </loads&gt;
</order&gt;
```

In the image below you can see that 19 and 124 are grouped together as they both have same address_line_1 (it's required that 19 appears in the order it does). The problem is that node 124 then appears later and is again grouped with 19. What I need to do is ignore load_split_ids that have already been iterated over or included in a previous group.

The only other way I can think of (maybe :-)) solving it is to create and msxml nodeset and then iterate over that, but I'd like to see if there's an alternative method



```<?xml version="1.0" encoding="UTF-8"?&gt;
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"  xmlns:msxsl="urn:schemas-microsoft-com:xslt"&gt;
    <xsl:output method="html"/&gt;


    <xsl:variable name="template_version"&gt;586-325-3186</xsl:variable&gt;
    <xsl:variable name="template_date"&gt;7th August 2016</xsl:variable&gt;
    <!-- Based on Shipments v51.243.225.55 --&gt;

     <xsl:variable name="currency_symbol"/&gt;



    <xsl:key name="unique_load_addresses_version_format" match="/order/loads[starts-with(load_haulier, 'Purolator')]/load_splits" use="concat(../load_address_1,'_',version_code,'_',despatch_tape_colour)"/&gt;


    <xsl:include href="Globals_pdf.xsl"/&gt;   
    <xsl:template match="order"&gt;
        <html&gt;
            <head&gt;
                <!-- PrinceXML: Adding UTF-8 stops browser interpreting &amp;#160; as A-circumflex followed by a <space&gt; --&gt;
                <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/&gt; 
                <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-2"/&gt;
                <style type="text/css"&gt;



                    body {font-family: Verdana, Arial, Helvetica, sans-serif; font-size:8pt;}
                    h1 {font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 22pt; font-weight: bold; margin: 0 0 10px 0;}
                    .outer { width: 100%; }
                    .tax { width: 100%;}
                    table {font-family: Verdana, Arial, Helvetica, sans-serif;cellspacing: 0px; cellpadding: 0px;  border-width: 0; border-collapse: collapse; border-spacing: 0px; width: 100%; }
                    td {vertical-align: top; font-family: Verdana, Arial, Helvetica, sans-serif; padding: 5px 1px 5px 1px; font-size: 8pt; border-width: 1pt; border-style: solid;  border-color: <xsl:value-of select="$color2"/&gt;;  }
                    th {text-align: left; vertical-align: bottom; background-color: LightSteelBlue; font-family: Verdana, Arial, Helvetica, sans-serif;  font-size: 8pt; font-weight: normal; padding: 5px 1px 5px 1px; border-width: 1pt; border-style: solid;  border-color: <xsl:value-of select="$color2"/&gt;; border-collapse: collapse; border-spacing: 0px; color: black;}


                    .bold { font-weight: bold; }
                    .grey {background-color: #dddddd; }

                    .proforma  { color:  black; }
                    .heading { vertical-align: bottom; text-align: center;}
                    .bottom_center { vertical-align: bottom;  text-align: center; }
                    .top_center { vertical-align: top; text-align: center; }
                    .top_left { vertical-align: top; text-align: left; }
                    .middle_left { vertical-align: middle; text-align: left; }
                    .middle_center { vertical-align: middle; text-align: center; }
                    .top_right { vertical-align: top;  text-align: right; }
                    .bottom_left { vertical-align: bottom;  text-align: left; }
                    .bottom_right { vertical-align: bottom; text-align: right; }

                    .left_indent {padding-left: 70px;}
                    .top_indent {padding-top: 35px;}



                    .label {font-weight: bold; width: 15%; padding-top: 2px; padding-bottom: 2px; padding-right: 5px; text-align: right; width: 30%; font-size: 12pt;}
                    .contents {padding-left: 5mm; width: 30%; padding-top: 2px; padding-bottom: 2px; width: 70%; font-size: 12pt;}

                    hr {border: none; background-color: black; height: 0.5pt;} 
                    .first_row { border-top: 2pt solid red; }
                    .red {color: #aa0000; }

                </style&gt;
            </head&gt;
            <body&gt;
                <table class="loads" style=""&gt;

                    <tr&gt;
                        <th&gt;S/P/I</th&gt;
                        <th&gt;Zone</th&gt;
                        <th&gt;Format</th&gt;
                        <th&gt;Address</th&gt;
                        <th&gt;Carrier</th&gt;
                     </tr&gt;

                    <xsl:for-each select="/order/loads[starts-with(load_haulier, 'Purolator')]/load_splits[generate-id() = generate-id(key('unique_load_addresses_version_format', concat(../load_address_1,'_',version_code,'_',despatch_tape_colour))[1])]"&gt;
                        <xsl:sort select="concat(version_code,'_',despatch_tape_colour)" data-type="text" /&gt;
                        <xsl:variable name="curr_address" select="../load_address_1"/&gt;

                        <tr&gt;
                            <td style="background-color: #fdf5e6; color: blue; border-top: 2px solid grey"&gt;Load/LoadSplitID: <xsl:value-of select="../LoadID"/&gt;/<xsl:value-of select="load_split_id"/&gt;</td&gt;
                            <td style="background-color: #fdf5e6; color: blue; border-top: 2px solid grey"&gt;<xsl:value-of select="version_code"/&gt;</td&gt;
                            <td style="background-color: #fdf5e6; color: blue; border-top: 2px solid grey"&gt;<xsl:value-of select="despatch_tape_colour"/&gt;</td&gt;
                            <td style="background-color: #fdf5e6; color: blue; border-top: 2px solid grey"&gt;<xsl:value-of select="../load_address_1"/&gt;</td&gt;
                            <td style="background-color: #fdf5e6; color: blue; border-top: 2px solid grey"&gt;</td&gt;
                        </tr&gt;

                        <xsl:for-each select="/order/loads[starts-with(load_haulier, 'Purolator') and load_address_1 = $curr_address]/load_splits"&gt;
                            <xsl:sort select="concat(version_code,'_',despatch_tape_colour)" data-type="text" order="ascending" /&gt;
                            <xsl:variable name="part_ref" select="load_despatch_code"/&gt;
                            <xsl:variable name="line_type"&gt;
                                <xsl:choose&gt;
                                    <xsl:when test="position() = 1"&gt;S</xsl:when&gt;
                                    <xsl:otherwise&gt;P</xsl:otherwise&gt;
                                </xsl:choose&gt;
                            </xsl:variable&gt;
                            <tr&gt;
                                 <td&gt;
                                    <xsl:attribute name="style"&gt;
                                        <xsl:choose&gt;
                                            <xsl:when test="position()=1"&gt;color: red; border-top: 2px solid black</xsl:when&gt;
                                            <xsl:when test="position()=last()"&gt;color: black;</xsl:when&gt;
                                        </xsl:choose&gt;
                                    </xsl:attribute&gt;
                                    <xsl:value-of select="load_split_id"/&gt;

                                </td&gt;
                                <td&gt;
                                    <xsl:attribute name="style"&gt;
                                        <xsl:choose&gt;
                                            <xsl:when test="position()=1"&gt;color: red; border-top: 2px solid black</xsl:when&gt;
                                            <xsl:when test="position()=last()"&gt;color: black;</xsl:when&gt;
                                        </xsl:choose&gt;
                                    </xsl:attribute&gt;
                                    <xsl:value-of select="version_code"/&gt;

                                </td&gt;
                                <td&gt;
                                    <xsl:attribute name="style"&gt;
                                        <xsl:choose&gt;
                                            <xsl:when test="position()=1"&gt;color: red; border-top: 2px solid black</xsl:when&gt;
                                            <xsl:when test="position()=last()"&gt;color: black;</xsl:when&gt;
                                        </xsl:choose&gt;
                                    </xsl:attribute&gt;
                                    <xsl:value-of select="despatch_tape_colour"/&gt;
                                </td&gt;
                                <td&gt;
                                    <xsl:attribute name="style"&gt;
                                        <xsl:choose&gt;
                                            <xsl:when test="position()=1"&gt;color: red; border-top: 2px solid black</xsl:when&gt;
                                            <xsl:when test="position()=last()"&gt;color: black;</xsl:when&gt;
                                        </xsl:choose&gt;
                                    </xsl:attribute&gt;
                                    <xsl:value-of select="../load_address_1"/&gt;
                                </td&gt;
                                <td&gt;
                                    <xsl:attribute name="style"&gt;
                                        <xsl:choose&gt;
                                            <xsl:when test="position()=1"&gt;color: red; border-top: 2px solid black</xsl:when&gt;
                                            <xsl:when test="position()=last()"&gt;color: black;</xsl:when&gt;
                                        </xsl:choose&gt;
                                    </xsl:attribute&gt;
                                    <xsl:value-of select="../load_haulier"/&gt;
                                </td&gt;
                            </tr&gt;
                        </xsl:for-each&gt;
                    </xsl:for-each&gt;
                </table&gt;
            </body&gt;
        </html&gt;
    </xsl:template&gt;
```



Any XSL wizards, got any suggestions?

TIA

Mark

Comment: Could you (a) minimize the example to only what's necessary to demonstrate the problem and (b) explain the required logic in words? How would one accomplish this task manually? -- I am especially puzzled by your requirement to sort first, then group. Does that mean you want to group only within sorted groups? I don't see that in your output (as far as I can understand it).



{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 0, 'CommentCount': 1, 'ContentLicense': 'CC BY-SA 3.0', 'CreationDate': '2016:00:08/16/16', 'FavoriteCount': None, 'PostTypeId': 1, 'Tags': '<xslt-1.0>', 'Title': 'XSL1.0 excluding previous nodes', 'ViewCount': 40, 'id': 38979620, 'user_AboutMe': '', 'user_AccountId': 1837030.0, 'user_DisplayName': 'mark1234', 'user_Reputation': 1090.0, 'user_Views': 325.0, 'user_id': 1667188.0}}