Is this only possible in XPath 2.0

I can't fugure out how to write an xpath to do the following in xpath 1.0:

Doc

<Plane>

<Seats Number="1" Window="No"/>

<Seats Number="2" Window="Yes"/>

</Plane>

I would like to concatinate the @Number & @Window fields on each node set returned

Desired Results:

1^NO

2^Yes

The problem is if I use concat in xpath 1.0 I only get a single string result.

Any ideas




Answer this question

Is this only possible in XPath 2.0

  • Jeff Johnson

    An XPath (1.0 or 2.0) expression cannot "create node-sets" -it can select a set of nodes that exist on the document(s) against which the XPath expression is evaluated.

    Also, it is not at all clear what you mea by "concatinate node-sets" In XPath concatenation is an operation defined on two strings, not on node-sets. Probably you meant the union operation But it doesn't produce two node-sets -- just one node-set, which is the union of the two arguments passed to the union operator.

    An XPath 2.0 can create a sequence of nodes (or other items), which is very different from a node-set (for example, the same node my occur more than once in a sequence).

    Therefore, could you, please, provide a more precise definition of your problem -- a complete small example would be most appropriate.

    Cheers,
    Dimitre Novatchev.


  • wirwin

    I guess this may be simplified to

    translate(concat(
      normalize-space(concat(/*/*[1]/@*[1], ' ', /*/*[1]/@*[2])), '&#xA;',
      normalize-space(concat(/*/*[2]/@*[1], ' ', /*/*[2]/@*[2])), '&#xA;',
      normalize-space(concat(/*/*[3]/@*[1], ' ', /*/*[3]/@*[2])), '&#xA;',
      normalize-space(concat(/*/*[4]/@*[1], ' ', /*/*[4]/@*[2])), '&#xA;',
      normalize-space(concat(/*/*[5]/@*[1], ' ', /*/*[5]/@*[2])), '&#xA;',
      normalize-space(concat(/*/*[ 6]/@*[1], ' ', /*/*[ 6]/@*[2])), '&#xA;',
      normalize-space(concat(/*/*[7]/@*[1], ' ', /*/*[7]/@*[2])), '&#xA;',
      normalize-space(concat(/*/*[ 8]/@*[1], ' ', /*/*[ 8]/@*[2])), '&#xA;',
      normalize-space(concat(/*/*[9]/@*[1], ' ', /*/*[9]/@*[2])), '&#xA;',
      normalize-space(concat(/*/*[10]/@*[1], ' ', /*/*[10]/@*[2])), '&#xA;',
      normalize-space(concat(/*/*[11]/@*[1], ' ', /*/*[11]/@*[2])), '&#xA;'
    ), ' ', '^')


  • Gurpreet Singh Gill

    Ok I'll try again:

    example:

    XML

    <Plane>

    <Seats Number="512" Window="No"/>

    <Seats Number="322" Window="Yes"/>

    <Seats Number="122" Window="No"/>

    <Seats Number="340" Window="Yes"/>

    </Plane>

    The following xpath would return multiple nodes.

    /Plane/Seats

    This is what I'm refefering to as a node set. I would like to be able to get the @Number & @Window value back in a node set like this (except stringing them together). Which sounds impossible because I guess this would be creating a new node set & populating the new concatinated data.

    I do not want a string returned.

    So that pretty much sums up the problem. I can do this in xpath 2.0.



  • y0ngb00n

    This is easy if the number of "Seats" elements is known (or can be obtained and then the XPath expression can be dynamically generated.

    In case one knows an expected maximum number of "Seats" elements, it is still possible to use an XPath expression like the following:

    concat(
    /*/*[not(1 > count(/*/*))][1]/@*[1],
    substring('^', 1, not(1 > count(/*/*))),
    /*/*[not(1 > count(/*/*))][1]/@*[2], '&#xA;',

    /*/*[not(2 > count(/*/*))][2]/@*[1],
    substring('^', 1, not(2 > count(/*/*))),
    /*/*[not(2 > count(/*/*))][2]/@*[2], '&#xA;',

    /*/*[not(3 > count(/*/*))][3]/@*[1],
    substring('^', 1, not(3 > count(/*/*))),
    /*/*[not(3 > count(/*/*))][3]/@*[2], '&#xA;',

    /*/*[not(4 > count(/*/*))][4]/@*[1],
    substring('^', 1, not(4 > count(/*/*))),
    /*/*[not(4 > count(/*/*))][4]/@*[2], '&#xA;',

    /*/*[not(5 > count(/*/*))][5]/@*[1],
    substring('^', 1, not(5 > count(/*/*))),
    /*/*[not(5 > count(/*/*))][5]/@*[2], '&#xA;',

    /*/*[not(6 > count(/*/*))] [ 6 ] /@*[1],
    substring('^', 1, not(6 > count(/*/*))),
    /*/*[not(6 > count(/*/*))] [ 6 ]/@*[2], '&#xA;',

    /*/*[not(7 > count(/*/*))][7]/@*[1],
    substring('^', 1, not(7 > count(/*/*))),
    /*/*[not(7 > count(/*/*))][7]/@*[2], '&#xA;',

    /*/*[not(8 > count(/*/*))] [ 8 ]/@*[1],
    substring('^', 1, not(8 > count(/*/*))),
    /*/*[not(8 > count(/*/*))] [ 8 ]/@*[2], '&#xA;',

    /*/*[not(9 > count(/*/*))][9]/@*[1],
    substring('^', 1, not(9 > count(/*/*))),
    /*/*[not(9 > count(/*/*))][9]/@*[2], '&#xA;',

    /*/*[not(10 > count(/*/*))][10]/@*[1],
    substring('^', 1, not(10 > count(/*/*))),
    /*/*[not(10 > count(/*/*))][10]/@*[2], '&#xA;',

    /*/*[not(11 > count(/*/*))][11]/@*[1],
    substring('^', 1, not(11 > count(/*/*))),
    /*/*[not(11 > count(/*/*))][11]/@*[2], '&#xA;'

    )

    When this XPath expression is evaluated on the xml document below:

    <Plane>

    <Seats Number="1" Window="No"/>

    <Seats Number="2" Window="Yes"/>

    <Seats Number="3" Window="No"/>

    <Seats Number="4" Window="Yes"/>

    </Plane>

    the wanted result will be produced:

    1^No
    2^Yes
    3^No
    4^Yes

    Cheers,
    Dimitre Novatchev


  • kenniejaydavis

    The problem is that I need the results to come back in seperate node sets. I don't need a way to add a line return to make it look like it multiple node sets.

    We have an application that takes in an xpath and executes it against a doc. If the results have multiple node results it seeds them in the database with a sequence. Every example provided so far only returns a single string. I need a 1 to many node set.



  • Tej62007

    Hi,

    The following XPath command will return you a string that contains the first element's number and window concataneted.

    concat(//Seats/@Number,' and ',//Seats/@Window)

    When you use concat, it return only stringtype, therefore it's not possible to navigate over it. There might be a hack to get around of this but I'm not aware of such thing.



  • markovuksanovic

    In my example (which is just what it is) the attribute @Number on seat is not a sequence or count. It reference's a possition on the plan. Let me modify the XML example to make this clear:

    <Plane>

    <Seats Number="512" Window="No"/>

    <Seats Number="322" Window="Yes"/>

    <Seats Number="122" Window="No"/>

    <Seats Number="340" Window="Yes"/>

    </Plane>

    This might be used to represent inventory availability.

    The result must be able to combine the 2 attributes in result node sets.



  • Asiye

    Right, that is the problem I need multiple node set result.

    Concat with only return a single string...



  • setuc

    Yes,

    however you confused everybody by using a phrase like "(except stringing them together)".

    What you actually wanted is by only using a single XPath expression to create a single text node out of two attribute nodes and to return the sequence of the nodes, produced in this way.

    This is possible in XPath 2.0, because of the "for" expression.

    One could use XSLT 1.0 for this purpose, or one could code an extension function and make it accessible in the XPath evaluation context, that would create the new text node.

    Cheers,
    Dimitre Novatchev


  • AVVIT

    we7313 wrote:

    In my example (which is just what it is) the attribute @Number on seat is not a sequence or count. It reference's a possition on the plan. Let me modify the XML example to make this clear:

    <Plane>

    <Seats Number="512" Window="No"/>

    <Seats Number="322" Window="Yes"/>

    <Seats Number="122" Window="No"/>

    <Seats Number="340" Window="Yes"/>

    </Plane>

    This might be used to represent inventory availability.

    The result must be able to combine the 2 attributes in result node sets.

    In the solution provided, the "Number" attribute is not used at all, so no assumption is being made that it will denote something specific.

    The solution works for your last example, producing, as required:

    512^No
    322^Yes
    122^No
    340^Yes

    Cheers,
    Dimitre Novatchev


  • Is this only possible in XPath 2.0