Search code examples
xmlxsltreplacetranslate

Missing something re: matching


I'm new to XSLT and have run into something I think should work but does not. I'm baffled and hope you can help.

I have the following code:

<xsl:template match="text()" name="multiReplace">
    <xsl:param name="pText" select="."/>

    <xsl:variable name="patterns">
        <pattern>
            <old>A</old>
            <new>B</new>
        </pattern>
        <pattern>
            <old>v</old>
            <new>w</new>
        </pattern>
    </xsl:variable>

    <xsl:if test="string-length($pText) >0">
        <xsl:variable name="matchingPatterns" select="$patterns[starts-with($pText, old/node())]"/>

    <!-- Do something with the tree fragment "matchingPatterns" -->

    </xsl:if>
</xsl:template>

As I understand it, the select="$patterns[starts-with($pText, old/node())]" should match only those elements of the patterns tree whose node old matches the start of the string $pText. Instead, $matchingPatterns contains all the nodes in the patterns tree. I know for a fact that $pText does not contain any capital 'A' characters but does contain lowercase 'v's.

Is there something obviously wrong that I'm missing?

Thanks for your help!

-j

p.s., the gist of this code comes from this question: XSL Multiple search and replace function. That code was written for XSLT 1; we're using 2 and it somehow didn't work correctly for me out of the box.


Solution

  • Given

    <xsl:variable name="patterns">
        <pattern>
            <old>A</old>
            <new>B</new>
        </pattern>
        <pattern>
            <old>v</old>
            <new>w</new>
        </pattern>
    </xsl:variable>
    

    in XSLT 2.0 the variable is a tree fragment consisting of a root node containing two pattern elements so your variable definition should be

    <xsl:variable name="matchingPatterns" select="$patterns/pattern[starts-with($pText, old)]"/>
    

    to select those pattern elements that meet the condition.

    As an alternative, use <xsl:variable name="matchingPatterns" select="$patterns[starts-with($pText, old)]"/> but then make sure you set up

    <xsl:variable name="patterns" as="element(pattern)*">
        <pattern>
            <old>A</old>
            <new>B</new>
        </pattern>
        <pattern>
            <old>v</old>
            <new>w</new>
        </pattern>
    </xsl:variable>
    

    In that case your patterns variable is a sequence of parentless pattern elements, not a tree fragment with a root node containing pattern elements.