Search code examples
distinctxpath-2.0altova

XPath 2.0: Finding number of distinct elements before first element with current node's value


Setup: I am using XPath 2.0. But inside Altova Stylevision, see my comment later on.

I have got the following XML structure:

    <?xml version="1.0" encoding="UTF-8"?>
    <entries>
        <bla>
            <blub>222</blub>
        </bla>
        <bla>
            <blub>222</blub>
        </bla>
        <bla>
            <blub>123</blub>
        </bla>
        <bla>
            <blub>234</blub>
        </bla>
        <bla>
            <blub>123</blub>
            <!--I want to find the number of distinct elements before the first occurance of a blub element with the same value as the current node - so for this node the result should be one (two times 222 before the first appearance of 123)-->
        </bla>
    </entries>

When parsing that I file I would like to know at each occurance of a blub: How many distinct values of blub's are there before the first occurance of a blub with the same value as the current node.

So basically first determining where the first occurance of a blub with the same value as the current node is, and then figuring out the number of distinct blubs before.

One of my problems is that Altova doesn't support the current() function. Quote: "Note that the current() function is an XSLT function, not an XPath function, and cannot therefore be used in StyleVision's Auto-Calculations and Conditional Templates. To select the current node in an expression use the for expression of XPath 2.0."

So any solution that could do without the current() function would be great ;)

Thanks all!

Stevo


Solution

  • If you need the first node with the same value, you can always start at the beginning and search it with /entries/bla[blub=string()][1]. (string without parameter should return the value of the current node)

    And then you can insert it in your expression and get

    count(distinct-values( /entries/bla[blub=string()][1]/preceding-sibling::bla/blub ))
    

    And if you need it for all blubs you can count it for all of them:

    for $x in /entries/bla/blub return count(distinct-values( /entries/bla[blub=string($x)][1]/preceding-sibling::bla/blub ))
    

    edit: it might however be slow to perform, so many loops. If distinct-values in that Stylevision preserves the order of the elements, the number of elements before a value is the index of that a value in the distinct value sequence.

    So you can the count for one node with index-of(distinct-values(/entries/bla/blub), string()) - 1 and the count for all nodes with

    for $x in /entries/bla/blub return index-of(distinct-values(/entries/bla/blub), $x) - 1
    

    And if it is possible to define new variables you could set $s to distinct-values(/entries/bla/blub) and simplify it to

    for $x in /entries/bla/blub return index-of($s, $x) - 1