Subject: Re: passing filtered tree to template
From: Stefan Hunziker <stefan@xxxxxxxxxxxxx>
Date: Thu, 16 Jun 2011 11:34:27 +0200
|
Hi Brandon
I have implemented your approach and it works perfectly
Thank you very much
Stefan
On Thu, Jun 9, 2011 at 2:17 PM, Brandon Ibach
<brandon.ibach@xxxxxxxxxxxxxxxxxxx> wrote:
> Here's an approach that works while keeping the "criteria" for which
> items to include in the caller. No guarantees about how the
> performance of this approach might scale. Features in XSLT 3.0 (or
> even XSLT 2.0, I suspect) would make this cleaner and probably perform
> better.
>
> The xsl:for-each inside your "items" template basically turns it into
> an "item" template, so I cleaned it up a bit by just making the
> template match "item" and moving the test to determine of the item is
> the first in its group into an xsl:if. I also made the code more
> concise by using attribute value templates, but this is purely a
> matter of taste, rather than functionality.
>
> Your "property = 'x'" filter also needs to be applied to any results
> of the key() function. I did this below, while keeping the filter out
> of the "item" template, by passing in the filtered set of items and
> checking for group membership using the same basic technique you used
> for node identity when checking to see if an item is the first in its
> group.
>
> <xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
> <xsl:template match="test">
> <myTest>
> <xsl:variable name="items" select="items/item[property = 'x']"/>
> <xsl:apply-templates select="$items">
> <xsl:sort select="group"/>
> <xsl:with-param name="items" select="$items"/>
> </xsl:apply-templates>
> </myTest>
> </xsl:template>
>
> <xsl:key name="groupKey" match="item" use="group"/>
> <xsl:template match="item">
> <xsl:param name="items" select="/.."/>
> <xsl:if test="count(. | key('groupKey', group)[count(. |
> $items) = count($items)][1]) = 1">
> <myGroup Name="{group}"
> Sum="{sum(key('groupKey',group)[count(. | $items) =
> count($items)]/amount)}"/>
> </xsl:if>
> </xsl:template>
> </xsl:stylesheet>
>
> Hope this helps.
>
> -Brandon :)
>
>
> On Tue, Jun 7, 2011 at 2:34 AM, Stefan Hunziker <stefan@xxxxxxxxxxxxx>
wrote:
>> Hi Abel
>>
>> thank you for your answer. Sorry when my instructions were confusing.
>> I give it another try, in fact the items template is a little bit more
>> complicated because I want to apply a grouping mechanism.
>>
>> given the following xml:
>>
>> <test>
>> <items>
>> <item>
>> <index>1</index>
>> <group>b</group>
>> <property>x</property>
>> <amount>1</amount>
>> </item>
>> <item>
>> <index>2</index>
>> <group>a</group>
>> <property>y</property>
>> <amount>3</amount>
>> </item>
>> <item>
>> <index>3</index>
>> <group>a</group>
>> <property>x</property>
>> <amount>6</amount>
>> </item>
>> </items>
>> </test>
>>
>> I want to process this stylesheet:
>>
>> <xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
>> <xsl:template match="test">
>> <myTest>
>> <xsl:variable name="xItems">
>> <xsl:copy-of select="items"/>
>> </xsl:variable>
>> <xsl:apply-templates
select="items[item/property='y']"/>
>> </myTest>
>> </xsl:template>
>>
>> <xsl:key name="groupKey" match="item" use="group"/>
>> <xsl:template match="items">
>> <xsl:for-each select="item[count(.| key('groupKey', group)[1]) = 1]">
>> <xsl:sort select="group"/>
>> <myGroup>
>> <xsl:attribute name="Name">
>> <xsl:value-of select="group"/>
>> </xsl:attribute>
>> <xsl:attribute name="Sum">
>> <xsl:value-of select="sum(key('groupKey',group)/amount)"/>
>> </xsl:attribute>
>> </myGroup>
>> </xsl:for-each>
>> </xsl:template>
>> </xsl:stylesheet>
>>
>>
>> So the target is to have a group list with the corresponding sum of
>> amount, so I don't have a "item" template, but only an "items". But
>> therefore only the property=x items should be processed. Is that more
>> clear?
>>
>> kind regards
>> Stefan
>>
>>
>>
>> On Mon, Jun 6, 2011 at 6:11 PM, Abel Braaksma <abel.online@xxxxxxxxx>
wrote:
>>> Hi Stefan,
>>>
>>> The easy way out here is to add the filter to the matching template
>>> instruction, and add another matching template for those that don't
match,
>>> or, if all "item" elements need to be processed in the same way, but item
>>> with property=x need to be processed with an extra instruction, something
>>> like this should work:
>>>
>>> <xsl:template match="items">
>>> <xsl:apply-templates select="item" />
>>> </xsl:template>
>>>
>>> <!-- called ONLY when property X is true -->
>>> <xsl:template match="item[property='x']">
>>> <myItem>
>>> <xsl:value-of select="index"/>
>>> </myItem>
>>> </xsl:template>
>>>
>>> <!-- called for all other situations (may leave empty if you don't want
to
>>> process them) -->
>>> <xsl:template match="item">
>>> <otherItem>
>>> <xsl:value-of select="index"/>
>>> </otherItem>
>>> </xsl:template>
>>>
>>> I have to note that I found your instruction a tad confusing, so if I
>>> misunderstood, please try to clarify with a simplified input/output
example
>>> of XML.
>>>
>>>
>>> Kind regards,
>>>
>>> Abel Braaksma
>>>
>>>
>>>
>>> On 6-6-2011 17:56, Stefan Hunziker wrote:
>>>>
>>>> Hi
>>>> I have the following problem: Given an xml like the following:
>>>>
>>>> <test>
>>>> <items>
>>>> <item>
>>>> <index>1</index>
>>>> <property>x</property>
>>>> </item>
>>>> <item>
>>>> <index>2</index>
>>>> <property>y</property>
>>>> </item>
>>>> <item>
>>>> <index>3</index>
>>>> <property>x</property>
>>>> </item>
>>>> </items>
>>>> </test>
>>>>
>>>>
>>>> and a stylesheet like:
>>>>
>>>>
>>>> <xsl:stylesheet version="1.0"
>>>> xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
>>>> <xsl:template match="test">
>>>> <myTest>
>>>> <xsl:variable name="xItems">
>>>> <xsl:copy-of select="items"/>
>>>> </xsl:variable>
>>>> <xsl:apply-templates
>>>> select="items[item/property='y']"/><!-- wrong try! -->
>>>> </myTest>
>>>> </xsl:template>
>>>>
>>>> <xsl:template match="items">
>>>> <xsl:for-each select="item">
>>>> <myItem>
>>>> <xsl:value-of select="index"/>
>>>> </myItem>
>>>> </xsl:for-each>
>>>> </xsl:template>
>>>> </xsl:stylesheet>
>>>>
>>>>
>>>>
>>>> I would like to pass only the items with property='x' to the items
>>>> matching template. The first try as written above of course doesn't
>>>> work, if there is an x item then the whole tree is passed, if there is
>>>> none, nothing is passed. I do further processing in the items
>>>> template, so I don't want to change it to match="item" or to apply the
>>>> filter in the items template.
>>>>
>>>> Any help is much appreciated!
>>>>
>>>> thanks, kind regards
>>>>
>>>> Stefan
>
>
--
****************************
stefan hunziker
kanalweg 10
ch-3315 bdtterkinden
tel +41 32 665 17 76
mob +41 79 455 30 62
email stefan@xxxxxxxxxxxxx
|