Sorry,
Found a minor issue with the posted solution (likely a pasting mistake).
Here is the corrected solution:
<xsl:stylesheet version="2.0" xmlns:xsl="
http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:my="my:my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<my:params xml:space="preserve">
<pattern>
<old>corelation</old>
<new>dependency</new>
</pattern>
<pattern>
<old>relation</old>
<new>tie</new>
</pattern>
<pattern>
<old>
</old>
<new><br/></new>
</pattern>
<pattern>
<old>quick</old>
<new>slow</new>
</pattern>
<pattern>
<old>fox</old>
<new>elephant</new>
</pattern>
<pattern>
<old>brown</old>
<new>white</new>
</pattern>
</my:params>
<xsl:variable name="vPatterns"
select="document('')/*/my:params/*"/>
<xsl:template match="/">
<xsl:sequence select="my:MultuReplace(/*)"/>
</xsl:template>
<xsl:function name="my:MultuReplace">
<xsl:param name="pText" as="xs:string*"/>
<xsl:variable name="vStartingIndexes" select=
"for $ind in 1 to string-length($pText),
$hasMatchingPattern in
exists($vPatterns[starts-with(substring($pText, $ind), old)])
return
$ind[$hasMatchingPattern]
"/>
<xsl:variable name="actualIndexes" select=
"for $pos in 1 to count($vStartingIndexes),
$ind in $vStartingIndexes[$pos]
return
if($pos = 1) then $ind
else
(for $prevInd in $vStartingIndexes[$pos -1],
$prevReplacementLength in
string-length($vPatterns[starts-with(substring($pText, $prevInd),
old)][1]/old)
return
if($prevReplacementLength le $ind - $prevInd)
then $ind
else ()
)
"/>
<xsl:variable name="vResultSequence" as="xs:string*">
<xsl:sequence select=
"for $pos in 1 to count($actualIndexes),
$indRepl in $actualIndexes[$pos],
$startUnprocessedText in
(if($pos = 1)
then 1
else
(for $indLastReplacedText in $actualIndexes[$pos -1],
$last-replacedText in
$vPatterns[starts-with(substring($pText, $indLastReplacedText),
old)][1]/old,
$lastReplacementLength in
string-length($last-replacedText)
return
$actualIndexes[$pos -1] +
string-length($last-replacedText)
)
)
return
( concat(
substring($pText, $startUnprocessedText, $indRepl -
$startUnprocessedText),
$vPatterns[starts-with(substring($pText, $indRepl),
old)][1]/new/string()
)
)
"/>
<xsl:sequence select=
"for $lastReplIndex in $actualIndexes[last()],
$last-replacedText in $vPatterns[starts-with(substring($pText,
$lastReplIndex), old)][1]/old,
$lastReplacementLength in string-length($last-replacedText)
return
substring($pText, $lastReplIndex + $lastReplacementLength)
"/>
</xsl:variable>
<xsl:sequence select="string-join($vResultSequence, '')"/>
</xsl:function>
</xsl:stylesheet>
Cheers,
Dimitre
On Sat, May 18, 2019 at 1:21 PM Dimitre Novatchev <dnovatchev@xxxxxxxxx>
wrote:
> This was an XSLT 1.0 recursive solution:
>
> https://stackoverflow.com/a/5283744/36305
>
> Based on this algorithm one can produce a non-recursive XSLT 2.0 solution
> (and even a single XPath 2 expression).
>
> Here is a first, non-polished but working non-recursive MultiReplace
> implementation in XSLT 2.0 -- just 58 lines and well-formatted. This
> implementation also solves the problem of overlapping replacement patterns:
>
> <xsl:stylesheet version="2.0" xmlns:xsl="
> http://www.w3.org/1999/XSL/Transform"
> xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:my="my:my">
> <xsl:output omit-xml-declaration="yes" indent="yes"/>
> <xsl:strip-space elements="*"/>
>
> <my:params xml:space="preserve">
> <pattern>
> <old>corelation</old>
> <new>dependency</new>
> </pattern>
> <pattern>
> <old>relation</old>
> <new>tie</new>
> </pattern>
> <pattern>
> <old>
</old>
> <new><br/></new>
> </pattern>
> <pattern>
> <old>quick</old>
> <new>slow</new>
> </pattern>
> <pattern>
> <old>fox</old>
> <new>elephant</new>
> </pattern>
> <pattern>
> <old>brown</old>
> <new>white</new>
> </pattern>
> </my:params>
>
> <xsl:variable name="vPatterns"
> select="document('')/*/my:params/*"/>
>
> <xsl:template match="/">
> <xsl:sequence select="my:MultuReplace(/*)"/>
> </xsl:template>
>
> <xsl:function name="my:MultuReplace">
> <xsl:param name="pText" as="xs:string*"/>
>
> <xsl:variable name="vStartingIndexes" select=
> "for $ind in 1 to string-length($pText),
> $hasMatchingPattern in
> exists($vPatterns[starts-with(substring($pText, $ind), old)])
> return
> $ind[$hasMatchingPattern]
> "/>
>
> <xsl:variable name="actualIndexes" select=
> "for $ind in $vStartingIndexes
> return $ind
> [position() = 1
> or
> (for $pos in position()[position() > 1],
> $prevInd in $vStartingIndexes[$pos -1],
> $prevReplacementLength in
> string-length($vPatterns[starts-with(substring($pText, $prevInd),
> old)][1]/old)
> return
> $prevReplacementLength le $ind - $prevInd
> )
> ]
> "/>
>
> <xsl:variable name="vResultSequence" as="xs:string*">
> <xsl:sequence select=
> "for $pos in 1 to count($actualIndexes),
> $indRepl in $actualIndexes[$pos],
> $startUnprocessedText in
> (if($pos = 1)
> then 1
> else
> (for $indLastReplacedText in $actualIndexes[$pos -1],
> $last-replacedText in
> $vPatterns[starts-with(substring($pText, $indLastReplacedText),
> old)][1]/old,
> $lastReplacementLength in
> string-length($last-replacedText)
> return
> $actualIndexes[$pos -1] +
> string-length($last-replacedText)
> )
> )
> return
> ( concat(
> substring($pText, $startUnprocessedText, $indRepl -
> $startUnprocessedText),
> $vPatterns[starts-with(substring($pText, $indRepl),
> old)][1]/new/string()
> )
> )
> "/>
>
> <xsl:sequence select=
> "for $lastReplIndex in $actualIndexes[last()],
> $last-replacedText in $vPatterns[starts-with(substring($pText,
> $lastReplIndex), old)][1]/old,
> $lastReplacementLength in string-length($last-replacedText)
> return
> substring($pText, $lastReplIndex + $lastReplacementLength)
> "/>
> </xsl:variable>
>
> <xsl:sequence select="string-join($vResultSequence, '')"/>
> </xsl:function>
> </xsl:stylesheet>
>
> When this transformation is applied on this source XML document:
>
> <t>a corelation between a quick brown fox and a dog</t>
>
> the wanted result is produced:
>
> *a dependency between a slow white elephant and a dog*
>
>
>
> Cheers,
> Dimitre
>
>
> On Thu, May 16, 2019 at 12:49 PM Dimitre Novatchev dnovatchev@xxxxxxxxx <
> xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:
>
>> https://stackoverflow.com/a/5283744/36305
>>
>> Cheers,
>> Dimitre
>>
>> On Thu, May 16, 2019 at 11:59 AM Rick Quatro rick@xxxxxxxxxxxxxx <
>> xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:
>>
>>> Hi,
>>>
>>>
>>>
>>> I have a look up file of find/change pairs that I have to apply to a
>>> text node in my XML document. I am using XSLT 2. Here is an example of the
>>> lookup file:
>>>
>>>
>>>
>>> <?xml version="1.0" encoding="UTF-8"?>
>>> <findchange_lookup>
>>> <findchange find="Eicas" change="EICAS"/>
>>> <findchange find="Ulb" change="ULB"/>
>>> </findchange_lookup>
>>>
>>> I am reading this in as a global variable, but I am not sure the best
>>> approach for doing multiple replacements on the node. I can use recursion
>>> like in XSLT 1, but I can't think of how to do this in XSLT 2. There could
>>> be any number of <findchange> elements in my lookup file. Any pointers
>>> would be appreciated. Thank you very much.
>>>
>>>
>>>
>>> Rick
>>>
>>>
>>>
>>> Rick Quatro
>>>
>>> Carmen Publishing Inc.
>>>
>>> rick@xxxxxxxxxxxxxxx
>>>
>>> 585-729-6746
>>>
>>> www.frameexpert.com/store/
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>> 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 <>)
|