Preceding with partial string

R

rnakawat

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="UniqueStreet" select="./Cell[@Name='Street']/
@Value"/>

<xsl:element name="street">
<xsl:attribute name="name">
<xsl:value-of select="$UniqueStreet"/>
</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="UniqueStreet" select="substring-after(./
Cell[@Name='Address']/@Value, ' ')"/>

said:
</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?
 
M

Martin Honnen

<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/#func-distinct-values and there is
xsl:for-each-group.


With XSLT 1.0 you need to use Muenchian grouping:

<xsl:stylesheet
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="substring-after(Cell[@Name =
'Address']/@Value, ' ')"/>
</street>
</xsl:for-each>
</root>
</xsl:template>

</xsl:stylesheet>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,817
Latest member
DicWeils

Latest Threads

Top