Re: [xsl] How to create xsl:key that has a composite value in its "use" attribute?

Subject: Re: [xsl] How to create xsl:key that has a composite value in its "use" attribute?
From: "Wendell Piez wapiez@xxxxxxxxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Sat, 15 Mar 2025 21:27:32 -0000
Indeed (now having tested my faulty memory), to gloss further what Dimitre
has just explained, with this input

<dir>
    <cars>
        <car vin="101" color="red"/>
        <car vin="102" color="green"/>
        <car vin="103" color="red"/>
        <car vin="104" color="red"/>
    </cars>
    <lots>
        <lot id="L">
            <car vin="101"/>
            <car vin="103"/>
        </lot>
        <lot id="M">
            <car vin="102"/>
        </lot>
        <lot id="N">
            <car vin="104"/>
        </lot>
    </lots>
</dir>

This XSLT works under XSLT 3.0 but not XSLT 1.0:

<xsl:key name="car-by-color" match="cars/car" use="@color"/>

<xsl:key name="lot-for-car" match="lot" use="car/@vin"/>

<xsl:template match="lot">
    <lot id="{@id}"/>
</xsl:template>

<xsl:template match="/">
    <set>
        <problem>
            <question>Which lots have red cars?</question>
            <answer>
                <xsl:apply-templates select="key('car-by-color','red') /
key('lot-for-car',@vin)"/>
            </answer>
        </problem>
    </set>
</xsl:template>

Dimitre says this works with XSLT 2.0 as well (and I believe him). In 1.0,
we might nest for-each instructions instead of chain the function calls,
but even under 1.0 we are (presumably) not performing whole tree traversals
to find elements.

Regards, Wendell

On Sat, Mar 15, 2025 at 4:45b/PM Dimitre Novatchev dnovatchev@xxxxxxxxx <
xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:

> > It definitely does not work in XSLT 1.0 even when using concat().
> > The reason is that in XPath 1.0 it is invalid to have an path-step be a
> function call,
> > so key() cannot be a step in the proposed XPath expression - not in
> XPath 1.0.
>
> What works even with XSLT 1.0 is this (just the relevant code):
>
>       <fir>
>         <xsl:for-each select="key('kNavForAirport', ARPT_IDENT)">
>           <xsl:copy-of select="key('kBoundaryForNav', concat(NAV_IDENT,
> '+', NAV_CTRY, '+', NAV_TYPE) ) / BDRY_IDENT"/>
>         </xsl:for-each>
>       </fir>
>
> Thanks,
> Dimitre.
>
> On Sat, Mar 15, 2025 at 1:31b/PM Dimitre Novatchev dnovatchev@xxxxxxxxx <
> xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:
>
>> Wendell,
>>
>> > Where you have
>> >
>> >   key('kBoundaryForNav', key('kNavForAirport', ARPT_IDENT)/(NAV_IDENT
>> || '+' || NAV_CTRY || '+' || NAV_TYPE))/BDRY_IDENT
>> >
>> > could not this be
>> >
>> >   key('kNavForAirport', ARPT_IDENT) / key('kBoundaryForNav', (NAV_IDENT
>> || '+' || NAV_CTRY || '+' || NAV_TYPE) ) / BDRY_IDENT
>>
>> The 2nd seems equally complex and is in fact slightly longer.
>>
>> It definitely does not work in XSLT 1.0 even when using concat(). The
>> reason is that in XPath 1.0 it is invalid to have an psth-step be a
>> function call, so key() cannot be a step in the proposed XPath expression
-
>> not in XPath 1.0.
>>
>> What works in XSLT 2.0 is this:
>>
>> key('kBoundaryForNav', key('kNavForAirport',
>> ARPT_IDENT)/(concat(NAV_IDENT, '+', NAV_CTRY, '+', NAV_TYPE)))/BDRY_IDENT
>>
>> It can be made more readable like this:
>>
>> key('kBoundaryForNav', key('kNavForAirport', ARPT_IDENT)
>>
>>  /(concat(NAV_IDENT, '+', NAV_CTRY, '+', NAV_TYPE))
>>        )/BDRY_IDENT
>>
>> Thanks,
>> Dimitre
>>
>> On Sat, Mar 15, 2025 at 12:49b/PM Wendell Piez wapiez@xxxxxxxxxxxxxxx <
>> xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:
>>
>>> Dimitre,
>>>
>>> Where you have
>>>
>>>   key('kBoundaryForNav', key('kNavForAirport', ARPT_IDENT)/(NAV_IDENT ||
>>> '+' || NAV_CTRY || '+' || NAV_TYPE))/BDRY_IDENT
>>>
>>> could not this be
>>>
>>>   key('kNavForAirport', ARPT_IDENT) / key('kBoundaryForNav', (NAV_IDENT
>>> || '+' || NAV_CTRY || '+' || NAV_TYPE) ) / BDRY_IDENT
>>>
>>> which is perhaps a little more intelligible? (Apologies if I am wrong in
>>> detail, I haven't tested.)
>>>
>>> Keeping in mind that calls on key() can be strung together since XSLT
>>> 1.0 (IIRC). In other words, this might be worth a try in Saxon 6.5 with
the
>>> concat() adjustment as you suggest.
>>>
>>> Cheers, Wendell
>>>
>>>
>>> On Sat, Mar 15, 2025 at 1:51b/PM Dimitre Novatchev dnovatchev@xxxxxxxxx
<
>>> xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:
>>>
>>>> I would use even this (can be XSLT 2.0 if || is done using concat() ):
>>>>
>>>> <xsl:stylesheet version="3.0" xmlns:xsl="
>>>> http://www.w3.org/1999/XSL/Transform";>
>>>> <xsl:output omit-xml-declaration="yes" indent="yes"/>
>>>> <xsl:key name="kNavForAirport" match="ANAV/row" use="ARPT_IDENT"/>
>>>> <xsl:key name="kBoundaryForNav" match="BDRY/row" use="NAV_IDENT || '+'
>>>> || NAV_CTRY || '+' || NAV_TYPE"/>
>>>>
>>>>   <xsl:template match="/*">
>>>>     <New-Document>
>>>>       <airports>
>>>>          <xsl:apply-templates select="ARPT/ARPT/row"/>
>>>>       </airports>
>>>>     </New-Document>
>>>>   </xsl:template>
>>>>
>>>>   <xsl:template match="ARPT/ARPT/row">
>>>>     <airport>
>>>>       <ARPT_IDENT><xsl:value-of select="ARPT_IDENT"/></ARPT_IDENT>
>>>>       <fir>
>>>>        <xsl:copy-of select="key('kBoundaryForNav',
>>>> key('kNavForAirport', ARPT_IDENT)/(NAV_IDENT || '+' || NAV_CTRY || '+'
||
>>>> NAV_TYPE))/BDRY_IDENT"/>
>>>>       </fir>
>>>>     </airport>
>>>>   </xsl:template>
>>>> </xsl:stylesheet>
>>>>
>>>> On Sat, Mar 15, 2025 at 9:27b/AM Martin Honnen martin.honnen@xxxxxx <
>>>> xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:
>>>>
>>>>>
>>>>> On 15/03/2025 17:19, Roger L Costello costello@xxxxxxxxx wrote:
>>>>> > <xsl:template match="ARPT/ARPT/row">
>>>>> >
>>>>> >      <result>
>>>>> >
>>>>> >          <xsl:for-each select="key('ARPT-to-ANAV', ARPT_IDENT)">
>>>>> >
>>>>> >              <xsl:sequence
>>>>> select="key('ANAV-to-BDRY',(NAV_IDENT,NAV_CTRY,NAV_TYPE))[TYPE eq
>>>>> '08']/BDRY_IDENT"/>
>>>>> >
>>>>> >        </xsl:for-each>
>>>>> >
>>>>> >      </result>
>>>>> >
>>>>> > </xsl:template>
>>>>>
>>>>>
>>>>> That could be written as
>>>>>
>>>>> <xsl:template match="ARPT/ARPT/row">
>>>>>
>>>>>      <result>
>>>>>
>>>>>              <xsl:sequence select="key('ARPT-to-ANAV', ARPT_IDENT) !
>>>>> key('ANAV-to-BDRY',(NAV_IDENT,NAV_CTRY,NAV_TYPE))[TYPE eq
>>>>> '08']/BDRY_IDENT"/>
>>>>>
>>>>>      </result>
>>>>>
>>>>> </xsl:template>
>>>>>
>>>>> I would think.
>>>>>
>>>>>
>>>>>
>>>>
>>>> XSL-List info and archive <http://www.mulberrytech.com/xsl/xsl-list>
>>>> EasyUnsubscribe <http://lists.mulberrytech.com/unsub/xsl-list/174322>
(by
>>>> email)
>>>>
>>>
>>>
>>> --
>>> ...Wendell Piez... ...wendell -at- nist -dot- gov...
>>> ...wendellpiez.com... ...pellucidliterature.org... ...pausepress.org...
>>> ...github.com/wendellpiez... ...gitlab.coko.foundation/wendell...
>>> XSL-List info and archive <http://www.mulberrytech.com/xsl/xsl-list>
>>> EasyUnsubscribe <http://lists.mulberrytech.com/unsub/xsl-list/782854> (by
>>> email)
>>>
>>
>>
>> XSL-List info and archive <http://www.mulberrytech.com/xsl/xsl-list>
>> EasyUnsubscribe <http://lists.mulberrytech.com/unsub/xsl-list/782854> (by
>> email)
>>
>
>
> XSL-List info and archive <http://www.mulberrytech.com/xsl/xsl-list>
> EasyUnsubscribe <http://lists.mulberrytech.com/unsub/xsl-list/174322> (by
> email <>)
>


--
...Wendell Piez... ...wendell -at- nist -dot- gov...
...wendellpiez.com... ...pellucidliterature.org... ...pausepress.org...
...github.com/wendellpiez... ...gitlab.coko.foundation/wendell...

Current Thread