Try this:
The error occurs because the inline function inside fold-left closes over
the global variable $find-change-map, and some XSLT 3.0 processors (Saxon
in particular) have trouble with global variable references captured in
closures within named functions. The fix is to pass the map as a parameter
to cp:find-change-text instead of referencing it as a free variable:
<xsl:function name="cp:find-change-text" as="xs:string">
<xsl:param name="text" as="xs:string"/>
<xsl:param name="changes" as="map(xs:string, xs:string)"/>
<xsl:sequence select="fold-left(map:keys($changes), $text,
function($t, $key) { replace($t, $key, $changes($key)) })"/>
</xsl:function>
Then update the call sites:
<xsl:variable name="text"
select="cp:find-change-text(normalize-space(title),
$find-change-map)"/>
The root cause: when an inline function (the lambda passed to fold-left) is
defined inside a named xsl:function, the processor compiles it as an
anonymous function object. If that lambda captures a *global* variable by
reference, certain processors flag it as an already-bound component during
static analysis b the global binding and the closure binding conflict.
Passing the map explicitly as a parameter keeps everything in the local
call stack and avoids the closure capture entirely.
A secondary issue worth noting: in your templates you have <xsl:text>[
/Title ({$text}) </xsl:text> b those curly braces only trigger AVT
expansion inside attribute values, not inside xsl:text. With
expand-text="yes" on the stylesheet element you'd use {$text} directly in
text content, which your stylesheet does have, but wrapped in xsl:text the
expansion still won't fire. You likely want either bare text content
or <xsl:value-of
select="$text"/> there.
*Kurt Cagle*
Editor in Chief
The Cagle Report
kurt.cagle@xxxxxxxxx
443-837-8725 <http://voice.google.com/calls?a=nc,%2B14438378725>
On Fri, Feb 27, 2026 at 1:28b/PM rick@xxxxxxxxxxxxxx <
xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:
> Hi All,
>
>
>
> I am applying a stylesheet via Oxygen using Saxon-EE 9.9.1.7 and it
> processes without errors. When I run the same stylesheet in Adobe
> FrameMaker using SaxonEE9-8-0-7J, I get this error:
>
>
>
> **** Component reference function anon:f_18205168#2 is already bound
>
>
>
> When I remove this function, I donbt get the error:
>
>
>
> <xsl:function name="cp:find-change-text" as="xs:string">
> <xsl:param name="text"/>
> <xsl:sequence select="*fold-left*(*map:keys*(*$find-change-map*),
> *$text*,
> *function*(*$text*, *$key*) { *replace*(*$text*, *$key*,
> *$find-change-map*(*$key*)) })"/>
> </xsl:function>
>
>
>
> Here is a partial input, followed by the stylesheet. I am outputting text.
>
>
>
> <?xml version="1.0" standalone="no"?>
> <map>
> <chapter name="Chapter1TOC.fm" page="24">
> <title>Chapter 1 Ethics and Professional Conduct</title>
> <practice-notes>
> <bookmark dest="G12.1038988">
> <title>? 1.1 Introduction</title>
> <bookmark dest="G12.1023242">
> <title>? 1.1:1 The Lawyerbs Creed</title>
> </bookmark>
> <bookmark dest="G12.1023245">
> <title>? 1.1:2 Notice of Grievance Process</title>
> </bookmark>
> </bookmark>
> <bookmark dest="G12.1023248">
> <title>? 1.2 Sources of Interpretation of Rules</title>
> </bookmark>
> </practice-notes>
> <forms>
> <bookmark name="Form1-1.fm" page="46">
> <title>Form 1-1 Letter Declining Representation</title>
> </bookmark>
> <bookmark name="Form1-2.fm" page="48">
> <title>Form 1-2 Letter Disclosing and Requesting Waiver of
> Potential Conflict with Current Client</title>
> </bookmark>
> <bookmark name="Form1-17.fm" page="123">
> <title>Form 1-17 Additional Clauses for Engagement
> Letters</title>
> <bookmark dest="G29.1726404">
> <title>Clause 1-17-1 Corporate Transparency Act</title>
> </bookmark>
> <bookmark dest="G29.1726774">
> <title>Clause 1-17-2</title>
> </bookmark>
> </bookmark>
> </forms>
> </chapter>
> </map>
>
>
>
> <?xml version="1.0" encoding="UTF-8"?>
> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
> xmlns:xs="http://www.w3.org/2001/XMLSchema"
> xmlns:cp="http://www.frameexpert.com/functions"
> xmlns:map="http://www.w3.org/2005/xpath-functions/map"
> exclude-result-prefixes="xs cp map"
> version="3.0"
> expand-text="yes">
>
> <xsl:output method="text" indent="no"/>
>
> <xsl:variable name="find-change-map" as="map(xs:string, xs:string)"
> select="*map*{*'—'* : '<emdash/>',
> *'–'* : '<endash/>',
> *'“'* : '<ldquote/>',
> *'”'* : '<rdquote/>',
> *'’'* : '<rsquote/>',
> *'§'* : '<section/>' }"/>
>
> <xsl:template match="/*map*">
> <xsl:text>[ /PageMode /UseOutlines /DOCVIEW
> pdfmark
</xsl:text>
> <xsl:apply-templates/>
> </xsl:template>
>
> <xsl:template match="*indexes*">
> <xsl:variable name="child-count" select="*count*(*index*)"/>
> <xsl:text>[ /Title (INDEXES) /Count -</xsl:text>
> <xsl:value-of select="*$child-count*"/><xsl:text> </xsl:text>
> <!-- Color is black; style is bold. -->
> <xsl:text>/*Color* [0 0 1] /*F* 2 /*Page* 0 /*OUT* </xsl:text>
> <xsl:text>*pdfmark*
</xsl:text>
> <xsl:apply-templates/>
> </xsl:template>
>
> <xsl:template match="*chapter*|*index*">
> <xsl:variable name="child-count" select="*count*(*bookmark*)"/>
> <!-- Call the function to replace special characters with
> elements. -->
> <xsl:variable name="text" select="*cp:find-change-text*(
> *normalize-space*(*title*))"/>
> <xsl:text>[ /Title ({*$text*}) </xsl:text>
> <!-- Reserved bookmarks get grey color. -->
> <xsl:if test="*matches*(*$text*,'reserved$')">
> <xsl:text>/Color [0.5 0.5 0.5] /F 0 </xsl:text>
> </xsl:if>
> <xsl:if test="*$child-count* > 0">
> <xsl:text>/Count -</xsl:text><xsl:value-of select="
> *$child-count*"/><xsl:text> </xsl:text>
> </xsl:if>
> <xsl:text>/Page </xsl:text><xsl:value-of select="*if*(*@page*)
> *then* *@page* *else* 0"/><xsl:text> </xsl:text>
> <xsl:text>/View [/XYZ -4 792 null] /OUT </xsl:text>
> <xsl:text>pdfmark
</xsl:text>
> <xsl:apply-templates/>
> </xsl:template>
>
> <xsl:template match="*bookmark*">
> <xsl:variable name="child-count" select="*count*(*bookmark*)"/>
> <!-- Call the function to replace special characters with
> elements. -->
> <xsl:variable name="text" select="*cp:find-change-text*(
> *normalize-space*(*title*))"/>
> <xsl:text>[ /Title ({*$text*}) </xsl:text>
> <!-- Reserved bookmarks get grey color. -->
> <xsl:if test="*matches*(*$text*,'reserved$')">
> <xsl:text>/Color [0.5 0.5 0.5] /F 0 </xsl:text>
> </xsl:if>
> <xsl:if test="*$child-count* > 0">
> <xsl:text>/*Count* -</xsl:text><xsl:value-of select="
> *$child-count*"/><xsl:text> </xsl:text>
> </xsl:if>
> <xsl:if test="*@page*">
> <xsl:text>/*Page* </xsl:text><xsl:value-of
select="*@page*"/><xsl:text>
> </xsl:text>
> </xsl:if>
> <xsl:if test="*@dest*">
> <xsl:text>/Dest /{*@dest*} </xsl:text>
> </xsl:if>
> <xsl:text>/*OUT* *pdfmark*
</xsl:text>
> <xsl:apply-templates/>
> </xsl:template>
>
> <xsl:mode on-no-match="shallow-skip"/>
>
> <xsl:function name="cp:find-change-text" as="xs:string">
> <xsl:param name="text"/>
> <xsl:sequence select="*fold-left*(*map:keys*(*$find-change-map*),
> *$text*,
> *function*(*$text*, *$key*) { *replace*(*$text*, *$key*,
> *$find-change-map*(*$key*)) })"/>
> </xsl:function>
>
> </xsl:stylesheet>
>
> Best regards,
>
> Rick
>
>
>
> Rick Quatro
>
> Carmen Publishing Inc.
>
> www.frameexpert.com
>
> rick@xxxxxxxxxxxxxxx
>
> 585-729-6746
>
>
> XSL-List info and archive <http://www.mulberrytech.com/xsl/xsl-list>
> EasyUnsubscribe <http://lists.mulberrytech.com/unsub/xsl-list/1217935> (by
> email <>)
|