5
votes

Attemping to build a template in XSLT to match on a specific Xpath case.

In this example XML document I want to match on all the text in the entire document except for in <x>:

<root>
 <tag1> I want this text </tag1>
 <tag2> I want this text </tag2>
 <x> I don't want to match on this text </x>
 <tag3> I want this text </tag3>
</root>

Any ideas on this Xpath? I'm trying to build a template for it to transform my document for this specific case.

What I have come up with some far is something like this that's not working:

<xsl:template match="text()[not(matches(.,x))]">

Any ideas?

2
Laterade, You may be interested in a shorter, better and more efficient solution, that works both in XSLT 2.0 and in XSLT 1.0.Dimitre Novatchev
@DimitreNovatchev: That's neither shorter (22 characters in each) nor more efficient (3 node matches instead of 2)BeniBela
@BeniBela, Is it so easy to call the black white? Your first XPath expression is: 1. calculating name(), 2. Of the parent, 3. Using matches() !!! which is not only less efficient than straight comparison, but also incorrect. Your second expression still has the reverse axis, which causes first going forward and then going backwords -- is this "efficient"? As for shortness, both your second expression and my expression occupy 22 bytes, but your first expression is 34 bytes long. Please understand and remember: We are here to promote best practices, and using a reverse axis when isn't such.Dimitre Novatchev
@DimitreNovatchev: Of course, I'm only talking about the second expression, since the first one was just there to explain, why Laterade's expression does not work. It does not matter for the efficiency, if it calculates forward or backward, only how much it calculates. And since the parent is cached anyways, using parent at the end instead of self in the middle is faster. (tried it with xsltproc and xidel on a 10000 line file)BeniBela
@BeniBela, In addition to the shortness/efficiency, there is also the point of readability/understandability.Dimitre Novatchev

2 Answers

4
votes

When you write . it takes the string value of the text node, not the node-name of the parent. And matches needs a string prarameter

You could write it as:

<xsl:template match="text()[not(matches(name(..),'x'))]">

Or better:

<xsl:template match="text()[not(parent::x)]">
2
votes

Much better -- Without any reverse axes:

<xsl:template match="*[not(self::x)]/text()">