Filtering, Grouping, Counting and Selecting specif

2019-09-19 02:36发布

问题:

I've got some XML that looks a little like this.

<Dealer>
  <Vehicle>
    <Model>KA</Model>
    <Series>Type A</Series>
    <Price>1000.00</Price>
  </Vehicle>
  <Vehicle>
    <Model>KA</Model>
    <Series>Type C</Series>
    <Price>1400.00</Price>
  </Vehicle>
  <Vehicle>
    <Model>KA</Model>
    <Series>Type A</Series>
    <Price>1100.00</Price>
  </Vehicle>
  <Vehicle>
    <Model>FOCUS</Model>
    <Series>Type B</Series>
    <Price>5000.00</Price>
  </Vehicle>
  <Vehicle>
    <Model>FIESTA</Model>
    <Series>Type A</Series>
    <Price>6000.00</Price>
  </Vehicle>
</Dealer>

What I'm trying to do is select 1 specific Model (EG: KA) then group Series into a distinct list (no duplicates), count how many there are within the Series, but only display the cheapest, using XSLT 1.0.

EG. My out put would look something like this:

KA Type A 2 in stock starting from 1000.00
KA Type C 1 in stock starting from 1400.00  

I've been looking at the Muenchian Method of grouping, but can't seem to marry it up with the other things I'm trying to achieve.

This is my attempt below. My thinking was to then just display the first item in each group, IE. the cheapest, and somehow do a count of each group.

<xsl:strip-space elements="*"/>

<xsl:template match="/Dealer">
   <xsl:apply-templates select="Vehicle[Model = 'KA']"/>
</xsl:template>

<xsl:key name="fSeries" match="Vehicle" use="Series" />
<xsl:template match="Vehicle">
   <xsl:for-each select="Vehicle[count(. | key('fSeries', Series)[1]) = 1]">
      <xsl:sort select="Price" />   
      <xsl:for-each select="key('fSeries', Series)">
         <xsl:sort select="Price" />
         <xsl:value-of select="Model" />&#32;<xsl:value-of select="Series" />&#32;<xsl:value-of select="Price" /><br />
      </xsl:for-each>
   </xsl:for-each>
</xsl:template> 

Would be very great of any help. Thanks.

回答1:

You have several problems, the first of them being the fact that Vehicle is not a child of Vehicle - so calling <xsl:for-each select="Vehicle..."> from the context of a template matching Vehicle will not accomplish anything.

The other thing is that your key matches all vehicles in a series, regardless of model.

Try it this way:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>

<xsl:key name="vehicle-by-series" match="Vehicle[Model='KA']" use="Series" />

<xsl:template match="/Dealer">
    <xsl:for-each select="Vehicle[Model='KA'][count(. | key('vehicle-by-series', Series)[1]) = 1]">
        <xsl:value-of select="Model"/>
        <xsl:text>: </xsl:text>
        <xsl:value-of select="Series"/>
        <xsl:text>, </xsl:text>
        <xsl:variable name="grp" select="key('vehicle-by-series', Series)" />
        <xsl:value-of select="count($grp)"/>
        <xsl:text> in stock, starting from </xsl:text>
        <xsl:for-each select="$grp">
            <xsl:sort select="Price" data-type="number" order="ascending"/>
            <xsl:if test="position() = 1">
                <xsl:value-of select="Price"/>
            </xsl:if>
        </xsl:for-each>
        <xsl:text>&#10;</xsl:text>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>