views:

91

answers:

2

Hello.

I just want to know if it's possible to use regular expressions in the match attribute of the template element. For example , suppose i have the follow xml document:

<greeting>
    <aaa>Hello</aaa>
    <bbb>Good</bbb>
    <ccc>Excellent</ccc>
    <dddline>Line</dddline>
</greeting>

Now the xslt to transform the above document:

<xsl:stylesheet>

    <xsl:template match="/">
        <xsl:apply-templates select="*"/>
    </xsl:template>

    <xsl:template match="matches(node-name(*),'line')">
        <xsl:value-of select="."/>
    </xsl:template>

</xsl:stylesheet>

When i try to use the syntax (matches(node-name(*),'line$')) in the match attribute of the template element , it retrieves a error message.Can i use regular expressions in the match attribute ?

Thanks very much

+1  A: 

In XSLT 1.0 (and 2.0, too), for your example (it's not a regex, though):

<xsl:template match="*[contains(name(), 'line')]">
  <xsl:value-of select="."/>
</xsl:template>

and to achieve an end-of-string match:

<xsl:template match="*[contains(concat(name(), '&#xA;'), 'line&#xA;')]">
  <xsl:value-of select="."/>
</xsl:template>

In XSLT 2.0 you can of course use the matches() function in place of contains().

Tomalak
@Dimitre: As you said, LF can't be part of the `name()`. So if you can't use XPath 2.0 (and regex), this would be a way of matching a name that contains the string `'line'` at its end, instead of anywhere. The OP seems to want that, because he mentions the regex `'line$'`, and he did not indicate the XSLT version he uses. I could have used space, or any other character that is illegal in names. So it's not at all meaningless or incorrect. ;-)
Tomalak
OK, I see now. For names this works.
Dimitre Novatchev
+3  A: 

Here is the correct XSLT 1.0 way of matching (in XSLT 2.0 use the matches() function with a real RegEx as the pattern argument):

Matching an element whose name contains 'line':

<xsl:template match="*[contains(name(), 'line')]"> 
  <!-- Whatever processing is necessary --> 
</xsl:template> 

Matching an element whose name ends in 'line':

<xsl:template match="*[substring(name(), string-length() -3) = 'line']"> 
  <!-- Whatever processing is necessary --> 
</xsl:template> 

@Tomalak provided another XSLT 1.0 way of finding names that end with a given string. His solution uses a special character that is guaranteed not to be ever present in any name. My solution can be applied to find if any string (not only a name of an element) ends with another given string.

In XSLT 2.x :

Use: matches(name(), '.*line$') to match names that end with the string "line"

This transformation:

when applied on theis XML document:

<greeting>
    <aaa>Hello</aaa>
    <bblineb>Good</bblineb>
    <ccc>Excellent</ccc>
    <dddline>Line</dddline>
</greeting>

Copies to the output only the element, whose name ends with the string "line":

<dddline>Line</dddline>

While this transformation (uses matches(name(), '.*line') ):

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"&gt;
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="*[matches(name(), '.*line')]">
  <xsl:copy-of select="."/>
 </xsl:template>

 <xsl:template match="*[not(matches(name(), '.*line'))]">
  <xsl:apply-templates select="node()[not(self::text())]"/>
 </xsl:template>
</xsl:stylesheet>

copies to the output all elements, whose names contain the string "line":

<bblineb>Good</bblineb>
<dddline>Line</dddline>
Dimitre Novatchev
First of all, thanks very much by your effort, it was the first time i post a doubt in this forum i am realy surprise of fast you had respond.I miss the version of the xslt that i pretend to work with, it will be 2.0 and yes i want to find the string 'line' at the of a string.One more time thnaks very much by your support
@pedromarquescosta: You are welcome. I have updated my answer with the requested XSLT 2.0 solution that uses RegEx.
Dimitre Novatchev