[xsl] Process map entries in defined order

Subject: [xsl] Process map entries in defined order
From: "Michael Mueller-Hillebrand michael.mueller-hillebrand@xxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Mon, 30 Jun 2025 06:58:39 -0000
Dear all,

I have a scenario with a user-defined set of substitutions which should be
applied to text nodes (a.k.a. strings). The XML is built like this:

        <substitute search="car" replace="auto"/>
        <substitute search="auto" replace="mobile"/>

As you can see from this little example the order of replacements is
important. I started with creating a map(xs:string, xs:string) for the search
and replace terms. Recursively applying the substitutions uses
map:keys($subs). Next, I learned from the specification that this function
bReturns the set of keys found in an input map, in arbitrary order.b

Since I want to honor the order given by the user, I think the only way out is
to change my map to include an integer key and feature the search and replace
string as the entry value: map(xs:integer, xs:string+) and always sort the
list of keys by number.

Or is there another smoother way handling this challenge?

Best regards,
Michael

FYI, this is the current function I am using:

                <xsl:function name="dy:applySubstitutions" as="xs:string">
                               <xsl:param name="text" as="xs:string"/>
                               <xsl:param name="subs" as="map(xs:string,
xs:string)"/>
                               <xsl:choose>
                                               <xsl:when test="map:size($subs)
eq 0">
                                                               <!-- no
substitutions left  -->
                                                               <xsl:sequence
select="$text"/>
                                               </xsl:when>
                                               <xsl:otherwise>
                                                               <!-- process
first, then do recursive call -->
                                                               <xsl:variable
name="key" select="map:keys($subs)[1]" as="xs:string"/>
                                                               <xsl:variable
name="result" select="$text => replace($key, map:get($subs, $key))"/>
                                                               <xsl:sequence
select="dy:applySubstitutions($result, map:remove($subs, $key))"/>
                                               </xsl:otherwise>
                               </xsl:choose>
                </xsl:function>

Current Thread