xsl-list
[Top] [All Lists]

Re: [xsl] recursive replacing strings with nodes

2010-02-19 08:25:54
On Fri, Feb 19, 2010 at 11:57, Martin Honnen 
<Martin(_dot_)Honnen(_at_)gmx(_dot_)de> wrote:
Here is a stylesheet trying to solve that

Wow, that seems to do what I want!  See comments inline where I try to
understand what is going on (so that when I google for this in a
couple years I can see what I thought was happening!).   Thanks
Martin.  (Someone off-list sent me a perl script that might accomplish
the same thing... but I'd prefer to do it in XSLT if possible ;-) )

For posterity:

<xsl:stylesheet
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
 version="2.0"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema";
 xmlns:mf="http://example.com/2010/mf";
 xmlns:functx="http://www.functx.com";
 exclude-result-prefixes="xsd mf functx">

 <xsl:function name="functx:escape-for-regex" as="xsd:string"
                >
   <xsl:param name="arg" as="xsd:string?"/>

   <xsl:sequence select="
    replace($arg,
            '(\.|\[|\]|\\|\||\-|\^|\$|\?|\*|\+|\{|\}|\(|\))','\\$1')
  "/>
 </xsl:function>

Include  the functx:escape-for-regex to escape the strings because I
intentionally made sure some of the strings in my sample had
regex-nasty characters like + and such (because my real input does).

 <xsl:param name="abbr-url" as="xsd:string" select="'test2010021902.xml'"/>
 <xsl:variable name="abbr" as="element(abbr)*"
select="doc($abbr-url)/root/choice/abbr"/>

Load nodeset of abbr elements as a variable from the lookuptable file
storing them as elements

Define the mf:replace function:
 <xsl:function name="mf:replace" as="node()*">
   <xsl:param name="str" as="xsd:string"/>
   <xsl:param name="abbr" as="element(abbr)*"/>
which has two parameters a string and an abbr element

   <xsl:choose>
     <xsl:when test="$abbr">
       <xsl:analyze-string select="$str"
regex="{functx:escape-for-regex($abbr[1])}">

analyze string provided looking for the first abbr (escaped for any regex)

         <xsl:matching-substring>
           <xsl:copy-of select="$abbr[1]/../expan/w"/>
         </xsl:matching-substring>

when it matches, go up to parent and copy-of the content of expan/w
         <xsl:non-matching-substring>
           <xsl:sequence select="mf:replace(., $abbr[position() gt 1])"/>
         </xsl:non-matching-substring>

when it doesn't match take the next thing in the implicit sequence
inside the abbr recursively calling mf:replace()

       </xsl:analyze-string>
     </xsl:when>
     <xsl:otherwise>
       <xsl:value-of select="$str"/>
     </xsl:otherwise>

If there isn't $abbr then put our the string.
   </xsl:choose>
 </xsl:function>


standard copy-all template:
 <xsl:template match="@* | node()">
   <xsl:copy>
     <xsl:apply-templates select="@*, node()"/>
   </xsl:copy>
 </xsl:template>


Everytime you come across a seg kick this off by copying it and for
its contents making a sequence of mf:replace()
 <xsl:template match="seg">
   <xsl:copy>
     <xsl:sequence select="mf:replace(., $abbr)"/>
   </xsl:copy>
 </xsl:template>

</xsl:stylesheet>



Thanks Martin!

-James

--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--

<Prev in Thread] Current Thread [Next in Thread>