Juicef
Juicef

Reputation: 316

Substring template matching xslt

I've struggled some time now. I just started with xslt, and I got things working just fine. Templates are used wherever possible and I've tried to keep myself from using for-loops.

My problem is this: I have a number of nodes with similar names, only difference is a postfix number from 1 to (currently) 5. These should all be transformed into a node without the numbers. So basically, here is what I have:

<title1>some title</title1>
<some_other_nodes>....</some_other_nodes>
<title2>some title2</title2>
.
.
.
<title5>....</title5>

And this is what I want:

<title>some title</title>
.
.
.
<title>some title2</title>
.
.
.
<title>....</title>

Is it possible to do substring matching with templates (matching just the title-part)?

Thanks for your help!

Upvotes: 2

Views: 3021

Answers (2)

Sean B. Durkin
Sean B. Durkin

Reputation: 12729

For elements of the form titleN, where N is some number, use a match condition like ...

(corrected:)

<xsl:template match="*[starts-with(name(),'title')]
                      [number(substring(name(),6))=number(substring(name(),6))]">
  etc...

Less generically, but quick and dirty, if you want SPECIFICALLY title1 through to title5, you might also think about ...

<xsl:template match="title1|title2|title3|title4|title5">

Upvotes: 2

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243549

Here is a true XSLT 2.0 solution that covers even the most complex cases, not covered by other answers:

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

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

 <xsl:template match="*[matches(name(), '^title.*?\d+$')]">
  <xsl:element name="{replace(name(), '^(title.*?)\d+$', '$1')}">
    <xsl:copy-of select="namespace::*"/>
    <xsl:apply-templates select="node()|@*"/>
  </xsl:element>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the following XML document:

<t>
    <title1>some title</title1>
    <some_other_nodes>....</some_other_nodes>
    <title2>some title2</title2> . . . 
    <title5>....</title5>
    <titleX253>Complex title</titleX253>
</t>

the wanted, correct result is produced:

<t>
      <title>some title</title>
      <some_other_nodes>....</some_other_nodes>
      <title>some title2</title> . . . 
    <title>....</title>
      <titleX>Complex title</titleX>
</t>

Do note the element:

<titleX253>Complex title</titleX253>

It should be transformed into:

<titleX>Complex title</titleX>

This is not what the answer by Sean Durkin does !

Upvotes: 1

Related Questions