6

How do I use apply-templates to select only those elements by name (not value) that end with a specific pattern? Assume the following xml...

<report>
  <report_item>
    <report_created_on/>
    <report_cross_ref/>
    <monthly_adj/>
    <quarterly_adj/>
    <ytd_adj/>
  </report_item>
  <report_item>
   ....
  </report_item>
</report>

I want to use <xsl:apply-templates> on all instances of <report_item> where descendant elements end with 'adj`, so, in this case, only monthly_adj, quaterly_adj, and ytd_adj would be selected and applied with the template.

<xsl:template match="report">
   <xsl:apply-templates select="report_item/(elements ending with 'adj')"/>
</xsl:template>
harpo
  • 41,820
  • 13
  • 96
  • 131
raffian
  • 31,267
  • 26
  • 103
  • 174

2 Answers2

11

I don't think that regular expression syntax is available in this context, even in XSLT 2.0. But you don't need it in this case.

<xsl:apply-templates select="report_item/*[ends-with(name(), 'adj')]"/>

* matches any node

[pred] performs a node test against the selector (in this case *) (where pred is a predicate evaluated in the context of the selected node)

name() returns the element's tag name (should be equivalent to local-name for this purpose).

ends-with() is a built-in XPath string function.

harpo
  • 41,820
  • 13
  • 96
  • 131
  • NEW STACKOVERFLOW WORLD RECORD....Fastest Answer Ever, LOL, you're right, not regex, just simple `ends with` was enough, thank you. – raffian Feb 13 '12 at 20:14
  • Glad to help :) I've updated the title to better match the question. – harpo Feb 13 '12 at 21:38
  • Note that ends-with is _not_ available in xslt **1.0**. See [use ends with in XSLT v1.0](http://stackoverflow.com/questions/11848780/use-ends-with-in-xslt-v1-0) for a 1.0 work-around. – R. Schreurs Apr 29 '14 at 09:56
2

Slightly neater solution (XSLT 2.0+ only):

<xsl:apply-templates select="report_item/*[matches(name(),'adj$')]"/>

Here is a self-test to prove it works. (Tested on Saxon).

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:fn="http://www.w3.org/2005/xpath-functions" 
                xmlns:xs="http://www.w3.org/2001/XMLSchema" 
                exclude-result-prefixes="xs fn">
 <xsl:output method="xml" indent="yes" encoding="utf-8" />
 <xsl:variable name="report-data">
  <report>
   <report_item>
     <report_created_on/>
     <report_cross_ref/>
     <monthly_adj>Jan</monthly_adj>
     <quarterly_adj>Q1</quarterly_adj>
     <ytd_adj>2012</ytd_adj>
   </report_item>
  </report>
 </xsl:variable>
 <xsl:template match="/" name="main">
  <reports-ending-with-adj>
   <xsl:element name="using-regex">
    <xsl:apply-templates select="$report-data//report_item/*[fn:matches(name(),'adj$')]"/> 
   </xsl:element>
   <xsl:element name="using-ends-with-function">
    <xsl:apply-templates select="$report-data//report_item/*[fn:ends-with(name(), 'adj')]"/>
   </xsl:element>
  </reports-ending-with-adj>
 </xsl:template>
</xsl:stylesheet>
Sean B. Durkin
  • 12,659
  • 1
  • 36
  • 65
  • The `match` worked for me. But I have an issue: http://xsltransform.net/pPzifp5/3 (I would like the order of `mOrder` to say which `li` I would like to display first, second, third...) Thank you. – Si8 Oct 28 '15 at 14:09
  • Or something like this: http://xsltransform.net/pPzifp5/4 (I am looking to display the parent LI and sub LI but it is multiplying for each iteration and duplicating. The empty LI I would like to not show and only show if it has a text.) Thanks for the help – Si8 Oct 28 '15 at 14:18
  • Post a question, and it will be answered. – Sean B. Durkin Oct 28 '15 at 20:29