1

This is related to a question I asked awhile ago. Given this xml:

<?xml version="1.0"?>
<paper>
<section><title>My Main Section</title>
    <para>My para with a <footnote num="a">text</footnote> footnote.</para>
    <section><title>my subsection</title>
    <para>more text with another <empty/><footnote num="b">more fn text.    </footnote> footnote.</para>
    </section>
</section>
</paper>

I want an xpath, from the /paper/section node that will give me just the first footnote (@num="a")

I have tried something along the lines of:

<xsl:template match="/paper/section">
    <section>
        <xsl:apply-templates select="//footnote[1]"/>
    </section>
</xsl:template>

but that returns both fn's. I assume because each fn is the first footnote node in its respective parent.

I tried a few variations:

        <xsl:apply-templates select="//footnote[position() = 1 ]"/>

that will return a footnote that is the first child of its parent, or the same as 1? The testing I did indicated they were the same.

I also tried a for-each loop, but wasn't able to pick anything up...

any ideas? bp

Community
  • 1
  • 1
badperson
  • 1,330
  • 3
  • 12
  • 33

3 Answers3

2

Instead of:

select="//footnote[1]"

try:

select="descendant::footnote[1]"

I will explain in a moment.


Actually, I don't have a good explanation; I can only quote from the XPath specification:

NOTE: The location path //para[1] does not mean the same as the location path /descendant::para[1]. The latter selects the first descendant para element; the former selects all descendant para elements that are the first para children of their parents.

michael.hor257k
  • 96,733
  • 5
  • 30
  • 46
2

I have tried something along the lines of:

<xsl:template match="/paper/section">
    <section>
        <xsl:apply-templates select="//footnote[1]"/>
    </section>
</xsl:template>

but that returns both fn's.

This is a FAQ. See for example this answer.

The XPath [] operator binds more strongly (has higher priority) than the // pseudo-operator.

This is why,

//x[1]

selects all x elements in the document, that are the first x child of their parent.

In XPath, as in math, to override the default priority of operators, one uses parentheses.

Use:

(//x)[1]

In this particular case, substituting x with the specific element name, gives us this expression:

(//footnote)[1]

And in case the first footnote element in a particular sub-tree of the document is wanted, use:

 (.//footnote)[1]

where the context (current) node for the evaluation of the expression is the root of the sub-tree


Explanation:

// isn't actually an XPath operator -- it is just a shorthand. To quote the W3C XPath 1.0 specification:

// is short for /descendant-or-self::node()/

This means that:

//x[1]

is expanded to:

/descendant-or-self::node()/x[1]

And this selects any x element that is the first x child of any node that is a descendant of the root (document) node.

Do note that the above expression is very different from:

/descendant::x[1]

and thus, the selected node-sets by the two expressions are generally different.

Community
  • 1
  • 1
Dimitre Novatchev
  • 230,371
  • 26
  • 281
  • 409
  • And you would need to add a leading dot if you want the first footnote _in this section_ as opposed to the first footnote _in the whole document_: `select="(.//footnote)[1]"` (the example in the question only has one section but the wording "I want an xpath, from the /paper/section node" suggests the real case has several) – Ian Roberts Apr 30 '15 at 16:04
0

Using descendant::para[x] still would give me all the items of Index x until the end of the tree (using it on Ranorex 8.1.2).

But by applying descendant::para[x][n] I get exactly the Nth element going down the Tree of Index X, or even better using descendant::para[][n] to just get the first Nth element to be found going through all children and their children.

Shams
  • 3,427
  • 5
  • 27
  • 45