1

I have the following XML file. I am writing an XPath query to return the concatenation of fname and weight for all orders with weight>50.

<purple> 
    <customer cid="1">
        <fname>John</fname> 
        <lname>Klingard</lname> 
        <apt>27</apt> 
        <street>30th Winstonhut St.</street> 
        <pobox>199183</pobox> 
    </customer>

    <customer cid="2"> 
        <fname>Anthony</fname> 
        <lname>Hurro</lname> 
        <apt>86</apt> 
        <street>Town St.</street> 
        <pobox>177162</pobox> 
    </customer> 

    <order oid="1"> 
        <eta>2016-04-23</eta> 
        <weight>55</weight> 
        <custid>1</custid>
    </order>

    <order oid="2"> 
        <eta>2016-05-03</eta> 
        <weight>75</weight> 
        <custid>2</custid> 
    </order>  
</purple>

I have written the query as:

concat(
 /purple/customer[@cid=/purple/order[weight>50]/custid]/fname/text(),
 /purple/order[weight>50]/weight/text())

The output is:

John55

The desired output is:

John55
Anthony75

Any advice on how I can achieve this?

kjhughes
  • 106,133
  • 27
  • 181
  • 240
Arjun
  • 817
  • 3
  • 16
  • 28

1 Answers1

1

XPath 1.0

XPath 1.0 cannot return multiple string concatenations like you request. Your output is closer to a rearrangement than a pure selection, so you should consider XSLT.

XPath 2.0

You can use a for loop in XPath 2.0:

for $c in /purple/customer[@cid=/purple/order[weight>50]/custid]
    return concat($c/fname, /purple/order[custid=$c/@cid]/weight)

will return

John55
Anthony75

as requested

kjhughes
  • 106,133
  • 27
  • 181
  • 240
  • This is interesting! I did manage to get close to the required output by using the '|' operator. Like this: purple/customer[@cid=/purple/order[weight>50]/custid]/fname/text() | purple/order[weight>50]/weight/text() – Arjun Mar 28 '16 at 16:01
  • Well, your XPath will return four text nodes, `John, Anthony, 55, 75`, not even in the requested order, so I'm not sure that qualifies as "close". You could probably enumerate them out and rearrange for some predetermined cases but would be hard pressed to generalize the approach when the needed number is not known in advance. – kjhughes Mar 28 '16 at 16:07
  • I understand what you mean. Is the execution always from left-to-right for the '|' operator? – Arjun Mar 28 '16 at 16:15
  • 1
    The union operator (`|`) returns its results in *document order*. So, your same XPath would return `55, 75, John, Anthony` if the `order` elements all came before the `customer` elements in the XML document. – kjhughes Mar 28 '16 at 16:23