Hi Rolf,
First off...
BTW, you stated that my concat is somehow ineffective. Does this mean
that several TEXT and VALUE-OF elements would be better ?
Yes, it is actually more efficient during execution (in all transformation
engines i have come across) to do several <xsl:text>'s and <xsl:value-of>'s
than one <xsl:value-of> with a concat(). The reason is that concat() is an
operation that takes time - and an operation that the transformation was
intending to do anyway... so you are almost doing the same thing twice by
having things like <xsl:value-of select="concat('literal',value,...)"/>.
Much the same as in many computer lanuguages - where you would avoid
concatenations - especially repeated concantenations of literal/static text.
If you reduce it to a simple test...
<?xml version="1.0"?>
<root>
<item>xxxxxxxxxxxxx</item>
<item>xxxxxxxxxxxxx</item>
<item>xxxxxxxxxxxxx</item>
<item>xxxxxxxxxxxxx</item>
<item>xxxxxxxxxxxxx</item>
<item>xxxxxxxxxxxxx</item>
<item>xxxxxxxxxxxxx</item>
<item>xxxxxxxxxxxxx</item>
<item>xxxxxxxxxxxxx</item>
<item>xxxxxxxxxxxxx</item>
<!-- repeat a few thousand times -->
</root>
and run these two stylesheets as comparisons...
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="
http://www.w3.org/1999/XSL/Transform">
<xsl
utput method="text"/>
<xsl:template match="/">
<xsl:for-each select="root/item">
<xsl:text>Item: </xsl:text>
<xsl:value-of select="."/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
and...
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="
http://www.w3.org/1999/XSL/Transform">
<xsl
utput method="text"/>
<xsl:template match="/">
<xsl:for-each select="root/item">
<xsl:value-of select="concat('Item: ',.,'
')"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
on MSXML 4.0, which you mentioned, the first stylesheet only takes only
about 30% of the time it takes for the second stylesheet.
And the main problem...
1) I guess macth="Pin" will match Pin at any level of what is
currently selected.
Right ?
Correct - so as with any match pattern you keep specifying it from right to
left until it matches the required nodes. As you have done.
2) I still have some problem when I have a kind of preselection and
the node NOT selected has also a Pin which would normally match.
So I have made a more complex code to demonstrate that. Please find it
below.
(have a look to ... select="Root/x/TEST[44 >= @Index and @Index >=
43]" )
Maybe you can explain why this happens.
You need to have a pretty good understanding of how the Muenchian technique
works... it works by saying "is this node the same as the first occurence of
these nodes with this specific value". Therefore, any filtering needs to be
applied consistently for it to work correctly.
Filtering whilst trying to distincts can be tricky at the best of times -
and would be far more tricky (with hideously complex XPaths) if trying to
persue the preceding method of finding distincts.
If you use keys, you will be able to do some of the filtering within the
keys - by making the selection filter part of the key selection value. And
it is as well to learn keys and become very familiar with them - as they are
extremely powerful and useful.
The down side to keys is that you cannot use variables in the @select -
which means any selective filtering needs to be placed as a value in the
select and then passed into the key() value. Which means you could do your
@CellType and @PinClass filtering within the keys - but the comparator on
@index would be impossible... so that would need to be added consistently as
a predicate filter.
Something like...
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="
http://www.w3.org/1999/XSL/Transform">
<xsl
aram name="idx_from" select="43"/>
<xsl
aram name="idx_to" select="44"/>
<xsl
aram name="cell_type" select="'M'"/>
<xsl
aram name="pin_class" select="'T'"/>
<xsl
utput method="text"/>
<!-- define a key that is capable of doing some of the filtering by
passing in key selection values -->
<xsl:key name="kSelectPins" match="TEST/Pin"
use="concat(../@CellType,'|',@PinClass)"/>
<!-- define the key that will filter and be used for finding distincts
with that filtering applied -->
<xsl:key name="kDistinctPins" match="TEST/Pin"
use="concat(../@CellType,'|',@PinClass,'|',@PinName)"/>
<xsl:variable name="TopNetPins"
select="key('kSelectPins',concat($cell_type,'|',$pin_class))[../
@index >=
$idx_from and ../
@index <= $idx_to]"/>
<xsl:variable name="MultiplePins"
select="$TopNetPins[count(key('kDistinctPins',concat(../@CellType,'|',@PinCl
ass,'|',@PinName))[../
@index >= $idx_from and ../
@index <= $idx_to])
> 1]"/>
<xsl:variable name="UniqueMultiplePins"
select="$MultiplePins[generate-id() =
generate-id(key('kDistinctPins',concat(../@CellType,'|',@PinClass,'|',@PinNa
me))[../
@index >= $idx_from and ../
@index <= $idx_to])]"/>
<xsl:template match="/">
<xsl:text>all pins of all test nodes ==> OK
</xsl:text>
<xsl:for-each select="$TopNetPins">
<xsl:value-of select="@PinName"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
<xsl:text>
multiple pins ==> OK
</xsl:text>
<xsl:for-each select="$MultiplePins">
<xsl:value-of select="@PinName"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
<xsl:text>
unique pins ==> OK
</xsl:text>
<xsl:for-each select="$UniqueMultiplePins">
<xsl:value-of select="@PinName"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
And yes, I have used concat() a fair bit - but not for serializing output.
HTH
Marrow
http://www.marrowsoft.com - home of Xselerator (XSLT IDE and debugger)
http://www.topxml.com/Xselerator
Rolf Kemper said:
Dear Marrow,
thank you for your good input. Your code is basically working.
But my real world is much more complex, and on top of that my
understanding about match seems to be wrong.
1) I guess macth="Pin" will match Pin at any level of what is
currently selected.
Right ?
2) I still have some problem when I have a kind of preselection and
the node NOT selected has also a Pin which would normally match.
So I have made a more complex code to demonstrate that. Please find it
below.
(have a look to ... select="Root/x/TEST[44 >= @Index and @Index >=
43]" )
Maybe you can explain why this happens.
In case of fail, the $UniqueMultiplePins node set is empty !!
BTW, you stated that my concat is somehow ineffective. Does this mean
that several TEXT and VALUE-OF elements would be better ?
Thank you very much for your kind help
Rolf
######### new data #############################
<?xml version="1.0" encoding="UTF-8"?>
<Root>
<E>
<!-- If we have the key match with pin only
the xslt does not work. If the maych is at least TEST/Pin
it is OK
-->
<Pin PinName="A" PinClass="T"/>
<!--<Pin PinName="AX" PinClass="T"/> -->
</E>
<x>
<!-- in case the TEST node below is not selected by Index
AND PinName="A" and CellType="M" matches
the result is wrong
-->
<TEST Index="42" CellType="M">
<Pin PinName="z" PinClass="R"/>
<!--<Pin PinName="AX" PinClass="T"/>-->
<Pin PinName="A" PinClass="T"/>
</TEST>
<TEST Index="43" CellType="M">
<Pin PinName="A" PinClass="T"/>
<Pin PinName="D" PinClass="R"/>
<Pin PinName="C" PinClass="R"/>
<Pin PinName="X" PinClass="R"/>
</TEST>
<TEST Index="44" CellType="M">
<Pin PinName="D" PinClass="R"/>
<Pin PinName="C" PinClass="R"/>
<Pin PinName="X" PinClass="R"/>
<Pin PinName="A" PinClass="T"/>
</TEST>
<TEST Index="45" CellType="M">
<Pin PinName="z" PinClass="R"/>
</TEST>
</x>
</Root>
############# new xslt ############################################
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="
http://www.w3.org/1999/XSL/Transform">
<xsl
utput method="text"/>
<xsl:key name="kDistinctPins" match="TEST/Pin" use="@PinName"/>
<!-- @Index >= 43 fails , @Index >= 42 OK -->
<xsl:variable name="Selected" select="Root/x/TEST[44 >= @Index and
@Index >= 43]"/>
<xsl:variable name="Macros" select="$Selected[@CellType='M']"/>
<xsl:variable name="TopNetPins"
select="$Macros/Pin[@PinClass='T']"/>
<xsl:variable name="MultiplePins"
select="$TopNetPins[count(key('kDistinctPins',@PinName)) > 1]"/>
<xsl:variable name="UniqueMultiplePins"
select="$MultiplePins[generate-id() =
generate-id(key('kDistinctPins',@PinName))]"/>
<xsl:template match="/">
<xsl:text>all pins of all test nodes ==> OK
</xsl:text>
<xsl:for-each select="$TopNetPins">
<xsl:value-of select="@PinName"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
<xsl:text>
multiple pins ==> OK
</xsl:text>
<xsl:for-each select="$MultiplePins">
<xsl:value-of select="@PinName"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
<xsl:text>
unique pins ==> OK
</xsl:text>
<xsl:for-each select="$UniqueMultiplePins">
<xsl:value-of select="@PinName"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
########## end ###################
"Marrow" <
[email protected]> wrote in message
Hi Rolf,
When comparing node-sets it is as well to remember that x != y is not quite
the same as not(x = y).
But anyway, I don't think it's worth trying to do what you want using the
preceding method for obtaining uniques - the Muenchian technique will be
much easier and yield far better performance, e.g.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="
http://www.w3.org/1999/XSL/Transform">
<xsl
utput method="text"/>
<xsl:key name="kDistinctPins" match="Pin" use="@PinName"/>
<xsl:variable name="TestNodes" select="Root/TEST/Pin"/>
<xsl:variable name="MultiplePins"
select="$TestNodes[count(key('kDistinctPins',@PinName)) > 1]"/>
<xsl:variable name="UniqueMultiplePins"
select="$MultiplePins[generate-id() =
generate-id(key('kDistinctPins',@PinName))]"/>
<xsl:template match="/">
<xsl:text>all pins of all test nodes ==> OK
</xsl:text>
<xsl:for-each select="$TestNodes">
<xsl:value-of select="@PinName"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
<xsl:text>
multiple pins ==> OK
</xsl:text>
<xsl:for-each select="$MultiplePins">
<xsl:value-of select="@PinName"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
<xsl:text>
unique pins ==> OK
</xsl:text>
<xsl:for-each select="$UniqueMultiplePins">
<xsl:value-of select="@PinName"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Btw, don't overuse the concat() function - especially not for literal
output... you are just doing concatenation where the transformation engine
will already serialize the output.
HTH
Marrow
http://www.marrowsoft.com - home of Xselerator (XSLT IDE and debugger)
http://www.topxml.com/Xselerator
Rolf Kemper said:
Dear Experts,
I got stuck with the following problem and need your help.
What I wnat to do is to get a set of distinct nodes.
Before the distinct I have selected the multiple occourences already
sucsessfully. However , the rest does not work as expected.
Hope someone can help on that.
Rolf
############################### DATA ################################
My XML DATA:
<?xml version="1.0" encoding="UTF-8"?>
<Root>
<TEST>
<Pin PinName="A" />
<Pin PinName="B" />
<Pin PinName="B" />
<Pin PinName="C" />
<Pin PinName="X" />
</TEST>
<TEST>
<Pin PinName="A" />
<Pin PinName="D" />
<Pin PinName="C" />
<Pin PinName="X" />
<Pin PinName="A" />
</TEST>
</Root>
My Test XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="
http://www.w3.org/1999/XSL/Transform"
xmlns:fo="
http://www.w3.org/1999/XSL/Format">
<xsl
utput method="text"/>
<xsl:variable name="NewLine" select="'
'"/>
<xsl:variable name="TestNodes" select="Root/TEST"/>
<xsl:variable name="MultiplePins" select="$TestNodes/Pin[@PinName =
preceding:
in/@PinName]"/>
<xsl:variable name="UniqueMultiplePins"
select="$MultiplePins[@PinName != preceding::*/@PinName]"/>
<xsl:template match="/">
<xsl:value-of select="concat('all pins of all test nodes ==>
OK ',$NewLine)"/>
<xsl:for-each select="$TestNodes/Pin">
<xsl:value-of select="concat(@PinName,$NewLine)"/>
</xsl:for-each>
<xsl:value-of select="$NewLine"/>
<xsl:value-of select="concat('multiple pins ==> OK ',$NewLine)"/>
<xsl:for-each select="$MultiplePins">
<xsl:value-of select="concat(@PinName,$NewLine)"/>
</xsl:for-each>
<xsl:value-of select="$NewLine"/>
<xsl:value-of select="concat('unique pins ==> NOT GOOD !!
',$NewLine)"/>
<xsl:for-each select="$UniqueMultiplePins">
<xsl:value-of select="concat(@PinName,$NewLine)"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
My results (gained by XMLSpy debug mode):
all pins of all test nodes ==> OK
A
B
B
C
X
A
D
C
X
A
multiple pins ==> OK
B
A
C
X
A
unique pins ==> NOT GOOD !!
B
A
C
X
A
( I expected B A C X )
#################### End #################################