xsl-list
[Top] [All Lists]

[xsl] Grouping output based on value in another document

2008-05-25 20:42:11
Hi Guys,

Long time reader, first time poster.

I have the following input document which we need to translate into an
aggregated output. The principle is that we filter out multiple instances of
the same alert and only output one of each type. A "Status" is assigned to
each Alert type (@alertid) in a mapping XML which holds several hundred
Alert ID's with their status mapping. Not that it matters but I have heavily
simplified these documents and the sample XSL to avoid confusion and to
focus on the problem I'm about to explain.

I have managed to get the required output working quite happily using
for-each-group, based on alert/@alertid as can be seen in the following
example documents

Input Document:

<someRoot>
  <machineID>ABC123</machineID>
  <alerts>
    <alert alertid="20260" details="Yet more" level="..." /> 
    <alert alertid="26554" details="Something 1" level="..." /> 
    <alert alertid="26554" details="Something 2" level="..." /> 
    <alert alertid="20676" details="Another thing 10" level="..." /> 
    <alert alertid="20676" details="Another thing 11" level="..." /> 
    <alert alertid="20676" details="Another thing 12" level="..." /> 
    <alert alertid="20012" details="More stuff" level="..." /> 
  </alerts>
</someRoot>

Reference Document:

<alertMapping>
    <Alerts>
        <Alert id="20260"  status="Administrator Review" />
        <Alert id="26554"  status="Administrator Review" />
        <Alert id="20676"  status="2nd Line Review" />
        <Alert id="20012"  status="Administrator Review" />
    </Alerts>
</alertMapping>

XSLT Document:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
xpath-default-namespace="http://www.tek.com/cerify/2007/03/22/reports";
version="1.0">
  <xsl:output method="xml" indent="yes" cdata-section-elements="" />
  <xsl:variable name="cpMappingLists"
select="document('mapping-document.xml')" />
    <xsl:key    name="cpALERTS"            match="Alert"   use="@id" />
  <xsl:template match="/">
    <xsl:variable name="machine">
      <xsl:value-of select="//machineID" />
    </xsl:variable>
    <outputSchema>
        <records>
        <xsl:for-each-group select="//alert" group-by="@alertid">
            <record>
                <machineID><xsl:value-of select="$machine"/></machineID>
                <alertType><xsl:value-of select="@alertid"/></alertType>
                <alertStatus>
                  <xsl:variable name="var1"
select="normalize-space(@alertid)" />
                  <xsl:for-each select="$cpMappingLists">
                    <xsl:value-of select="key( 'cpALERTS', string($var1)
)/@status"/>
                  </xsl:for-each>
                </alertStatus>
            </record>
        </xsl:for-each-group>
        </records>
    </outputSchema>
  </xsl:template>
</xsl:stylesheet>

Output Document #1:

<outputSchema>
  <records>
    <record>
        <machineID>ABC123</machineID>
      <alertType>20260</alertType>
      <alertStatus>Administrator Review</alertStatus>
    </record>
    <record>
        <machineID>ABC123</machineID>
      <alertType>26554</alertType>
      <alertStatus>Administrator Review</alertStatus>
    </record>
    <record>
        <machineID>ABC123</machineID>
      <alertType>20676</alertType>
      <alertStatus>2nd Line Review</alertStatus>
    </record>
    <record>
        <machineID>ABC123</machineID>
      <alertType>20012</alertType>
      <alertStatus>Administrator Review</alertStatus>
    </record>
  </records>
</outputSchema>

HOWEVER, I have now been asked to output only "one record for each Status"
to further simplify the lives of the consumer of the output. They are
apparently able to obtain a full list of alerts but they need to be nudged
into knowing they they are needed too, so one record for each type of Status
is what they now want. The output looking as follows:

Output Document #2

<outputSchema>
  <records>
    <record>
        <machineID>ABC123</machineID>
      <alertStatus>Administrator Review</alertStatus>
    </record>
    <record>
        <machineID>ABC123</machineID>
      <alertStatus>2nd Line Review</alertStatus>
    </record>
  </records>
</outputSchema>

This now looks to me like grouping on the Alert/@status in the MAPPING
DOCUMENT after I have mapped the values through. Anyone have any idea how it
can be accomplished. I have been looking at this for several hours now but
my feeble C# developer brain is in a flip trying to work out how to work
this declaritevly. Is there an elegant solution, a way to create a nodeset
from the grouping using xsl:variable and perhaps map the new values into
that nodeset then use for-each-group on it again ?

Any help GREATLY appreciated

Al


--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--

<Prev in Thread] Current Thread [Next in Thread>