1

I'm finding a way to use the xpath preceding/preceding-sibling functions to count the number of tag over the iteration on multiple xml file.

I'm using the 'collection' function to "merge" multiple xml, as below:

          <?xml version='1.0'?>
        <xsl:stylesheet version='2.0' xmlns:fo="http://www.w3.org/1999/XSL/Format"    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
            <xsl:output indent="yes"/>
            <xsl:variable name="input" select="collection('./docs.xml')"/>

            <xsl:template name="genTOC">
            ...

                <xsl:for-each select="$input/library">
                    <xsl:value-of select="count (preceding::library) +1" />
            ...

Where docs.xml contains reference to a series of xml file structured like below:

<library>
    <book>
        <title>The Art of Computer Programming</title>
        <price>198</price>
        <author>Donald Knuth</author>
        <ISBN>0201485419</ISBN>
    </book>
    <book>
        <title>The C Programming Language</title>
        <price>46.96</price>
        <author>Brian Wilson Kernighan</author>
        <ISBN>0131103628</ISBN>
    </book>
</library>

But seems that I'm not able to count the preceding as they are in another xml file. I've tried also with

count (../preceding::library)
profires
  • 13
  • 2

1 Answers1

1

I think you simply want

            <xsl:for-each select="$input/library">
                <xsl:value-of select="position()" />

If you really think you need to navigate the collection then you can create a temporary tree (fragment) within a variable

<xsl:variable name="my-library">
  <xsl:copy-of select="$input/library"/>
</xsl:variable>

<xsl:for-each select="$my-library/library">
  <xsl:value-of select="1 + preceding-sibling::library"/>
</xsl:for-each>

but of course you consume much more memory doing that compared to simply processing the input collection.

Martin Honnen
  • 160,499
  • 6
  • 90
  • 110
  • This of course resolve the specific problem, thanks! But generally speaking is not clear why my way was not working – profires Oct 06 '14 at 14:34
  • If you use `collection` to load a collection of documents then you end up with a sequence of document nodes while XPath tree and axes navigation is defined on a single tree, there are no axes to navigate within different trees. – Martin Honnen Oct 06 '14 at 14:39
  • +1 good answer as usual. Martin, can you help me understand on more general principle -- e.g. from the spec -- why `preceding::` doesn't cross documents, but `position()` does? E.g. the spec at http://www.w3.org/TR/xpath20/#axes says "the preceding axis contains all nodes that are descendants of the root of the tree in which the context node is found", but I'm not sure how we know that "the root of the tree" means a document root, and the collection cannot be considered a tree with its own root. – LarsH Oct 06 '14 at 14:43
  • I guess `position()` in this case is referring to position in the list that for-each is iterating over, so the number it returns has nothing to do with document trees and collections - right? – LarsH Oct 06 '14 at 14:45
  • @LarsH So using collection there is no way to use axes navigation? Is there an alternative way to 'collect' documents and let me able to use axes navigation? – profires Oct 06 '14 at 14:50
  • If you look at http://www.w3.org/TR/xquery-operators/#func-position then it defines `position()` as returning `the context position from the dynamic context`. And http://www.w3.org/TR/xslt20/#focus defines "The context position is the position of the context item within the sequence of items currently being processed [..] When an instruction such [..] xsl:for-each is used [...], the first item in the sequence is processed with a context position of 1, the second item with a context position of 2, and so on.] The context position is returned by the XPath expression position().". – Martin Honnen Oct 06 '14 at 14:52
  • 1
    @profires, I have edited the answer to show you how to create a temporary tree fragment in which the `library` element nodes copied from the input collection are sibling nodes. – Martin Honnen Oct 06 '14 at 14:57