Search

This isn't a Symphony specific problem, but you might be able to help me anyway.

What I'd like to do is to add markup to a string by using regular expressions, these regex patterns will be stored in a separate file and the same string needs to be iterated over all these patterns. Let me give you an example:

patterns.xml: <patterns> <pattern> <regex>\d+\smetr(es|e)</regex> </pattern> <pattern> <regex>\d+\s(km/h|mph)</regex> </pattern> <pattern> <regex>\d+\s*secon(ds|d)</regex> </pattern> </patterns>

data.xml: <section> <para>This is a paragraph with <em>three</em> matches: 24 metres, 120 km/h and 60 seconds.</para> </section>

desired result: <section> <para>This is a paragraph with <em>three</em> matches: <match>24 metres</match>, <match>120 km/h</match> and <match>60 seconds</match>.</para> </section>

The XSLT I've used for this looks like this: <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

&lt;xsl:template match="section"&gt;
    &lt;xsl:apply-templates/&gt;
&lt;/xsl:template&gt;

&lt;xsl:template match="text()"&gt;
    &lt;xsl:apply-templates select="doc('patterns.xml')/patterns/pattern[1]"&gt;
        &lt;xsl:with-param name="text" select="current()"/&gt;
    &lt;/xsl:apply-templates&gt;
&lt;/xsl:template&gt;

&lt;xsl:template match="pattern"&gt;
    &lt;xsl:param name="text"/&gt;

    &lt;xsl:choose&gt;
    &lt;xsl:when test="following-sibling::pattern"&gt;

        &lt;xsl:variable name="x"&gt;
            &lt;xsl:analyze-string select="$text" regex="{regex}"&gt;
                &lt;xsl:matching-substring&gt;
                    &lt;match&gt;
                        &lt;xsl:copy-of select="."/&gt;
                    &lt;/match&gt;
                &lt;/xsl:matching-substring&gt;
                &lt;xsl:non-matching-substring&gt;
                    &lt;xsl:copy-of select="."/&gt;
                &lt;/xsl:non-matching-substring&gt;
            &lt;/xsl:analyze-string&gt;
        &lt;/xsl:variable&gt;

        &lt;xsl:apply-templates select="following-sibling::pattern[1]"&gt;
            &lt;xsl:with-param name="text" select="$x"/&gt;
        &lt;/xsl:apply-templates&gt;

    &lt;/xsl:when&gt;
        &lt;xsl:otherwise&gt;

            &lt;xsl:variable name="x"&gt;
                &lt;xsl:analyze-string select="$text" regex="{regex}"&gt;
                    &lt;xsl:matching-substring&gt;
                        &lt;match&gt;
                            &lt;xsl:copy-of select="."/&gt;
                        &lt;/match&gt;
                    &lt;/xsl:matching-substring&gt;
                        &lt;xsl:non-matching-substring&gt;
                            &lt;xsl:copy-of select="."/&gt;
                        &lt;/xsl:non-matching-substring&gt;
                &lt;/xsl:analyze-string&gt;
            &lt;/xsl:variable&gt;

            &lt;xsl:apply-templates select="$x" mode="output"/&gt;

        &lt;/xsl:otherwise&gt;
    &lt;/xsl:choose&gt;
&lt;/xsl:template&gt;

&lt;xsl:template match="match[not(preceding-sibling::match=.)]" mode="output"&gt;
    &lt;match&gt;
        &lt;xsl:value-of select="."/&gt;
    &lt;/match&gt;
&lt;/xsl:template&gt;

&lt;xsl:template match="*" mode="output"&gt;
    &lt;xsl:apply-templates mode="#current"/&gt;
&lt;/xsl:template&gt;

&lt;/xsl:stylesheet&gt;

The transformation starts at the matching template of the text() node.

The problem with this code is that I only get the last match marked up (the \d+\s*secon(ds|d) or eg 12 seconds). This because the xsl:analyze-string is only able to a string and not a node-set, so even if the input string in the second iteration is correct with a <match/> this element will be stripped. If I use "psuedo markup" like #match# ... #/match# the script works correctly since we're only dealing with a string.

This is based on code from David Carlisle at http://www.dpawson.co.uk/xsl/sect2/replace.html#d9701e322.

Maybe I'm thinking all wrong about this, so please help me back on the right track! :)

(My formatting isn't the best (the regex in patterns.xml is kinda messed up) but I think you get the picture.)

Create an account or sign in to comment.

Symphony • Open Source XSLT CMS

Server Requirements

  • PHP 5.3-5.6 or 7.0-7.3
  • PHP's LibXML module, with the XSLT extension enabled (--with-xsl)
  • MySQL 5.5 or above
  • An Apache or Litespeed webserver
  • Apache's mod_rewrite module or equivalent

Compatible Hosts

Sign in

Login details