Preceding with partial string

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • rnakawat@gmail.com

    #1

    Preceding with partial string

    I seem to have a problem using the preceding:: on substrings of the
    value. I'll try to explain with an example:

    Let's say I had a XML that look like:

    <Root>
    <Row>
    <Cell Name="Street" Value="2nd Street" />
    </Row>
    <Row>
    <Cell Name="Street" Value="Meadow Lane" />
    </Row>
    <Row>
    <Cell Name="Street" Value="2nd Street" />
    </Row>
    <Row>
    <Cell Name="Street" Value="2nd Street" />
    </Row>
    <Row>
    <Cell Name="Street" Value="Meadow Lane" />
    </Row>

    </Root>

    Let's say I want to find the distinct streets. This is straight
    forward and may look something like:


    <xsl:template match="Root">
    <xsl:element name="root">


    <xsl:for-each select="./Row[Cell[@Name = 'Street' and not(@Value =
    preceding::Cell[@Name= 'Street']/@Value) ]]">

    <xsl:variable name="UniqueStr eet" select="./Cell[@Name='Street']/
    @Value"/>

    <xsl:element name="street">
    <xsl:attribut e name="name">
    <xsl:value-of select="$Unique Street"/>
    </xsl:attribute>

    <!-- This is where I would reiterate through the list to get the
    list of residents
    that live on that block -->
    </xsl:element>
    </xsl:for-each>
    </xsl:element>
    </xsl:template>

    This returns what I expect:

    <root>
    <street name="2nd Street"/>
    <street name="Meadow Lane"/>
    </root>

    But let's say the address contained street numbers, and I needed to
    strip out the street numbers when trying to look for unique street
    names.


    <Root>
    <Row>
    <Cell Name="Address" Value="1345 2nd Street" />
    </Row>
    <Row>
    <Cell Name="Address" Value="332 Meadow Lane" />
    </Row>
    <Row>
    <Cell Name="Address" Value="333 2nd Street" />
    </Row>
    <Row>
    <Cell Name="Address" Value="8534 2nd Street" />
    </Row>
    <Row>
    <Cell Name="Address" Value="556 Meadow Lane" />
    </Row>

    </Root>

    <xsl:template match="Root">
    <xsl:element name="root">


    <xsl:for-each select="./Row[Cell[@Name = 'Address' and
    not(substring-after(@Value, ' ') = substring-
    after(preceding ::Cell[@Name= 'Address']/@Value, ' ')) ]]">

    <xsl:variable name="UniqueStr eet" select="substri ng-after(./
    Cell[@Name='Address']/@Value, ' ')"/>

    <xsl:element name="street">
    <xsl:attribut e name="name"><xs l:value-of select="$Unique Street"/
    ></xsl:attribute>
    <!-- This is where I would reiterate through the list to get the
    list of residents
    that live on that block -->
    </xsl:element>
    </xsl:for-each>
    </xsl:element>
    </xsl:template>

    This yields the output:

    <root>
    <street name="2nd Street"/>
    <street name="Meadow Lane"/>
    <street name="Meadow Lane"/>
    </root>

    Can someone explain why that is happening and how I can fix it?
  • Martin Honnen

    #2
    Re: Preceding with partial string

    rnakawat@gmail. com wrote:
    <xsl:for-each select="./Row[Cell[@Name = 'Street' and not(@Value =
    preceding::Cell[@Name= 'Street']/@Value) ]]">
    <xsl:for-each select="./Row[Cell[@Name = 'Address' and
    not(substring-after(@Value, ' ') = substring-
    after(preceding ::Cell[@Name= 'Address']/@Value, ' ')) ]]">
    Can someone explain why that is happening and how I can fix it?
    The first comparison compares two node-sets (one with the single
    attribute @Value, one with all @Value attributes of preceding::Cell
    elements).
    The second comparison however compares the single @Value attribute to
    the string result of substring-after applied to the node-set of @Value
    attributes of preceding::Cell elements and that way you only compare to
    one preceding attribute, not to all.

    With XSLT 2.0 you could use

    <xsl:for-each select="./Row[Cell[@Name = 'Address' and
    not(substring-after(@Value, ' ') = preceding::Cell[@Name=
    'Address']/@Value/substring-after(., ' ')) ]]">

    to make sure you compare to a sequence and not a string value but that
    solution does not exist in XSLT 1.0.

    And XSLT 2.0 has other (easier) ways to identify distinct values, there
    is the function distinct-values
    http://www.w3.org/TR/xpath-functions...istinct-values and there is
    xsl:for-each-group.


    With XSLT 1.0 you need to use Muenchian grouping:

    <xsl:styleshe et
    xmlns:xsl="http ://www.w3.org/1999/XSL/Transform"
    version="1.0">

    <xsl:key name="by-street"
    match="Row"
    use="substring-after(Cell[@Name = 'Address']/@Value, ' ')"/>

    <xsl:template match="Root">
    <root>
    <xsl:for-each
    select="Row[generate-id() = generate-id(key('by-street',
    substring-after(Cell[@Name = 'Address']/@Value, ' '))[1])]">
    <street>
    <xsl:value-of select="substri ng-after(Cell[@Name =
    'Address']/@Value, ' ')"/>
    </street>
    </xsl:for-each>
    </root>
    </xsl:template>

    </xsl:stylesheet>
    --

    Martin Honnen
    http://JavaScript.FAQTs.com/

    Comment

    Working...