Federico
Federico

Reputation: 3920

Self axis in xslt

<element>
  <bye>do not delete me</bye>
  <hello>do not delete me</hello>
  <hello>delete me</hello>
  <hello>delete me</hello>
</element>

Applied to the above xml, this deletes all the nodes except the first hello child of /element:

<xsl:template match="hello[not(current() = parent::element/hello[1])]" />

Why these ones doesn't work? (assuming the first node is not a text node)

<xsl:template match="hello[not(self::hello/position() = 1)]" />
<xsl:template match="hello[not(./position() = 1)]" />

Or this one?

<xsl:template match="hello[not(self::hello[1])]" />

What is the self axis selecting? Why isn't this last example equivalent to not(hello[1])?

Upvotes: 0

Views: 4152

Answers (2)

Michael Kay
Michael Kay

Reputation: 163575

Using position() on the RHS of the "/" operator is never useful -- and in XSLT 1.0, which is the tag on your question, it's not actually permitted.

In XSLT 2.0, the result of the expression X/position() is a sequence of integers 1..count(X). If the LHS is a singleton, like self::E, then count(X) is one so the result is a single integer 1.

Upvotes: 2

michael.hor257k
michael.hor257k

Reputation: 117102

First, you are wrong when you say that:

This deletes all the nodes except the first hello child of /element

The truth is that it deletes (if that's the correct word) any hello child of /element whose value is not the same as the value of the first one of these. For example, given:

XML

<element>
    <hello>a</hello>
    <hello>b</hello>
    <hello>c</hello>
    <hello>a</hello>
</element>

the template:

<xsl:template match="hello[not(current() = parent::element/hello[1])]" />

will match the second and the third hello nodes - but not the first or the fourth.

Now, with regard to your question: in XSLT 1.0, position() is not a valid location step - so this:

<xsl:template match="hello[not(self::hello/position() = 1)]" />

should return an error.

In XSLT 2.0, the pattern hello[not(self::hello/position() = 1)] will not match any hello element - because there is only one node on the self axis, and therefore its position is always 1.

Similarly:

<xsl:template match="hello[not(./position() = 1)]" />

is invalid in XSLT 1.0.

In XSLT 2.0, ./position() will always return 1 for the same reason as before: . is short for self::node() and there is only one such node.

Finally, this template:

<xsl:template match="hello[not(self::hello[1])]" />

is looking for a node that doesn't have (the first instance of) itself. Of course, no such node can exist.

Upvotes: 3

Related Questions