0

I have following xml file. I need to find members are in $c which are not in $v:

(C) - (V) = desired result


let $c := /transport/trips/trip
let $v := /transport/trips/trip
where (data($c/@vehicle)="PKR856") 
return
<result2>
        {$v/(from|to|through)/string()} 
        {$c/(from|to|through)/string()} 
</result2>

Now I wan to subtract them and here is my code:

let $c := /transport/trips/trip
let $v := /transport/trips/trip
where (data($c/@vehicle)="PKR856") 
return
<result2>
    { $c/(from|to|through)/string()[not(. = $v/(from|to|through)/string())]} 
</result2>

I have tried this also is not workoing:

let $c := /transport/trips/trip/
let $v := /transport/trips/trip/(from|to|through)/string()
where (data($c/@vehicle)="PKR856") 
return
<result2>
    { $c/(from|to|through)/string()[not(. = $v)]} 
</result2>

output:

internal error code, argument

EDIT

Here is the XML file:

  <trips>
  <trip driver="d2345" vehicle="PKR856" date="12-DEC-2007">
    <from>London</from>
    <to>Newcastle</to>
    <through stop="1">Leicester</through>
    <through stop="2">Nottingham</through>
    <time>1</time>
  </trip>
  <trip driver="d6767" vehicle="UUQ007" date="10-MAY-2008">
    <from>Paris</from>
    <to>Rome</to>
    <through stop="1">Lyon</through>
    <through stop="2">Milan</through>
    <time>15</time>
  </trip>
  <trip driver="d2345" vehicle="PKR856" date="14-DEC-2007">
    <from>Paris</from>
    <to>Amsterdam</to>
    <through stop="2">Brussel</through>
    <through stop="1">Mons</through>
    <time>4</time>
  </trip>
</trips>

I need to return name of cities has not been visited by specific vehicle number?

I have tried these but is not working:

let $driver-cities := /trips/trip[@vehicle="PKR856"]/(from, to, through)/string()
return /trips/trip/(from, to)/string()[not(. = $driver-cities)]

I actually change the answer to:

let $c := /transport/trips/trip/(from|to|through)/text()
let $v := /transport/trips/trip[@vehicle eq "PKR856"]/(from|to|through)/text()
return
<result>
            { $c except $v} 
</result>
Bernard
  • 4,240
  • 18
  • 55
  • 88

2 Answers2

0

You could use the except operator to gain the difference of your two sets. Perhaps something like the following would work for you:

let $c := /transport/trips/trip
let $v := /transport/trips/trip[@vehicle eq "PKR856"] 
return

    $c except $v

Although as one of your sets is the complete set of all trip elements, the following produces the same result, and seems simpler to me:

/transport/trips/trip[@vehicle ne "PKR856"]

In collaboration with @Bernard, I believe the simplest desired answer is:

let $x := /transport/trips/trip[@vehicle ne "PKR856"]/(from|to|through)/text()
return
    <result>{$x}</result>
adamretter
  • 3,885
  • 2
  • 23
  • 43
  • Thanks for your answer but this is returning trips which is not done by specific vehicle. My concern is name of cities is not visited by specific vehicle. – Bernard Jun 09 '14 at 13:29
  • This is probably what I need but I get error: $c/(from|to|through)/string() except $v/(from|to|through)/string() – Bernard Jun 09 '14 at 13:32
  • You get an error because `except` operates on sequences of nodes and not on sequences of atomic types (e.g. strings). – adamretter Jun 09 '14 at 14:12
0

In XQuery 3.0 you can use the group by clause to find all vehicles that a city has been visited by. This can then be used to filter the results for those cities not visited by a specific vehicle:

let $vehicle := 'UUQ007'
for $trip in //trip
let $curr-vehicle := $trip/@vehicle/string()
for $city in $trip/(from, through, to)/string()
group by $city
where not($curr-vehicle = $vehicle)
return $city

This returns London Newcastle Leicester Nottingham Amsterdam Brussel Mons for your example document. If you set $vehicle := 'PKR856', the result is Rome Lyon Milan. I tried this in the newest version of BaseX.

If your processor does not support XQuery 3.0, the following query is probably less efficient but computes the same result in XQuery 1.0:

let $vehicle := 'UUQ007'
for $city in distinct-values(//trip/(from, through, to))
where not(//trip[@vehicle=$vehicle]/(from, through,to) = $city)
return $city
Leo Wörteler
  • 4,191
  • 13
  • 10