This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.
Use Case "R" ============ Q4: Tries to set Annabel Lee's rating to "B". But Annabel Lee was inserted (Q1) without any rating, so "replace value of" would have an empty target. Use Case "Parts" ================ The intro talks about a "partlist.xml", but the queries access a "part-list.xml" Q3: Neither solution 1, nor solution 3 lead to the expected result. Solution 1 doesn't delete piston, window and lock. The recursive function is solution 2 is also incorrect, as it deletes in "part-tree.xml" at the first call and in "part-list.xml" at subsequent calls. Q4: The note says that "as last into" should be used if position is important, but the expected result shows that the "radio" element is inserted as the first child of "car", not as the last one. Use Case "SOAP" =============== A few typos: * count($returnDepartingAirports)>1 (the one is missing) * has a call to currentdateTime() instead of current-dateTime() * should use string() instead of string-value() * call to local:airports($in) fails because $in is undefined; local:airports($out//env:Body) should be used Use Case "Address Book" ======================= - Typo: a comma is missing after "do replace value of $v2/contact with $v1/contact" I believe the current version of the address book use case raises a replace-replace conflict. The reason is that there is a loop within which we do the same replace: for $a in doc("archive.xml")/archived-agenda/entry, $v1 in doc("copy1.xml")/agenda-version/entry, $v2 in doc("copy2.xml")/agenda-version/entry where $a/name = $v1/name and $v1/name = $v2/name ... return ... do replace value of doc("archive.xml")/*/last-synch-time with current-dateTime() here doc("archive.xml")/*/last-synch-time keeps pointing to the same node and therefore there will be multiple replaces over the same node in the pending update list, which raises a conflict when applying them. - Jerome
This seems to solve the address book use case - it sure would be easier with the scripting extensions. for $a in doc("archive.xml")/archived-agenda/entry, $v1 in doc("copy1.xml")/agenda-version/entry, $v2 in doc("copy2.xml")/agenda-version/entry where $a/name = $v1/name and $v1/name = $v2/name return if ($a/contact = $v1/contact and $v1/contact=$v2/contact) then () else if ($v1/contact = $v2/contact) then replace value of node $a/contact with $v1/contact else if ($a/contact = $v1/contact) then ( replace value of node $a/contact with $v2/contact, replace value of node $v1/contact with $v2/contact ) else if ($a/contact = $v2/contact) then ( replace value of node $a/contact with $v1/contact, replace value of node $v2/contact with $v1/contact ) else ( insert node <fail> <arch>{ $a }</arch> <v1>{ $v1 }</v1> <v2>{ $v2 }</v2> </fail> into doc("log.xml")/log ) , replace value of node doc("archive.xml")/*/last-synch-time with current-dateTime()
I believe this fixes the errors in Use Case "SOAP": <pre> declare namespace env="http://www.w3.org/2003/05/soap-envelope"; declare namespace m="http://travelcompany.example.org/reservation"; declare namespace n="http://mycompany.example.com/employees"; declare namespace p="http://travelcompany.example.org/reservation/travel"; (: A clarification is needed only if there are no : airports or more than one for a given city. If : there is precisely one, there is no need to : ask for information on that city. :) declare function local:airportChoices($city as xs:string) { let $airports := collection("airports")[CITY = $city] return if (count($airports) = 0) then <error> No airports found for {$city}!</error> else if (count($airports) > 1) then <airportChoices> { for $c in $airports/CODE return (string( $c ), " ") } </airportChoices> else () }; (: Make sure that each airport is unambiguous. If there is : more than one airport for a city, ask for clarification. : : The primer only shows the error condition, so it is not : clear what to do if there are no errors. Here, we simply : return the airports in the itinerary. :) declare function local:airports($in as element(env:Envelope)) { let $departureDeparting := $in//p:departure/p:departing let $departureDepartingAirports := collection("airports")[CITY = $departureDeparting] let $departureArriving := $in//p:departure/p:arriving let $departureArrivingAirports := collection("airports")[CITY = $departureArriving] let $returnDeparting := $in//p:return/p:departing let $returnDepartingAirports := collection("airports")[CITY = $returnDeparting] let $returnArriving := $in//p:return/p:arriving let $returnArrivingAirports := collection("airports")[CITY = $returnArriving] return if ( count($departureDepartingAirports)=0 or count($departureDepartingAirports)>1 or count($departureArrivingAirports)=0 or count($departureArrivingAirports)>1 or count($returnDepartingAirports)=0 or count($returnDepartingAirports)>1 or count($returnArrivingAirports)=0 or count($returnArrivingAirports)>1 ) then <p:itineraryClarification> <p:departure> <p:departing> { local:airportChoices($departureDeparting) } </p:departing> <p:arriving> { local:airportChoices($departureArriving) } </p:arriving> </p:departure> <p:return> <p:departing> { local:airportChoices($returnDeparting) } </p:departing> <p:arriving> { local:airportChoices($returnArriving) } </p:arriving> </p:return> </p:itineraryClarification> else <p:itinerary> <p:departure> <p:departing>{$departureDeparting}</p:departing> <p:arriving>{$departureArriving}</p:arriving> </p:departure> <p:return> <p:departing>{$returnDeparting}</p:departing> <p:arriving>{$returnArriving}</p:arriving> </p:return> </p:itinerary> }; declare variable $msg external; copy $out := $msg/env:Envelope modify ( replace value of node $out//m:dateAndTime with fn:current-dateTime(), replace node $out//env:Body with <env:Body> { local:airports($out//env:Body) } </env:Body> ) return $out </pre>
Created attachment 483 [details] Fixed SOAP query. I think this fixes the SOAP bug.
I think this fixes the Use Case "R" Q4: let $user := doc("users.xml")/users/user_tuple[name="Annabel Lee"] return if ($user/rating) then replace value of node $user/rating with "B" else insert node <rating>B</rating> into $user
[quote]Q4: The note says that "as last into" should be used if position is important, but the expected result shows that the "radio" element is inserted as the first child of "car", not as the last one.[/quote] But that's the point. I show a query that doesn't specify position, and it winds up first, which might be unexpected. In subsequent text, I then say that you can put it in a particular position, e.g. by specifying "as last". I don't think this is a bug.
[quote]Q3: Neither solution 1, nor solution 3 lead to the expected result. Solution 1 doesn't delete piston, window and lock. The recursive function is solution 2 is also incorrect, as it deletes in "part-tree.xml" at the first call and in "part-list.xml" at subsequent calls.[/quote] I believe this is correct for solution 1: for $pt in doc("part-tree.xml")//part[@name="car"]//part, $pl in doc("part-list.xml")//part where $pt/@partid eq $pl/@partid return delete nodes $pl I believe this is correct for solution 2: declare updating function local:delete-subtree($p as element(part)) { for $child in doc("part-list.xml")//part where $p/@partid eq $child/@partof return ( delete nodes $child, local:delete-subtree($child) ) }; for $p in doc("part-list.xml")//part[@name="car"] return local:delete-subtree($p)
Closed on behalf of Jonathan; please reopen if it is not satisfactory.
Seems to work. Although the use of the 'current-dateTime' function will make it hard to use it as a test case... Thanks! - Jerome (In reply to comment #1) > This seems to solve the address book use case - it sure would be easier with > the scripting extensions. > > for $a in doc("archive.xml")/archived-agenda/entry, > $v1 in doc("copy1.xml")/agenda-version/entry, > $v2 in doc("copy2.xml")/agenda-version/entry > where $a/name = $v1/name > and $v1/name = $v2/name > return > if ($a/contact = $v1/contact and $v1/contact=$v2/contact) > then () > else > if ($v1/contact = $v2/contact) > then replace value of node $a/contact with $v1/contact > else > if ($a/contact = $v1/contact) > then ( > replace value of node $a/contact with $v2/contact, > replace value of node $v1/contact with $v2/contact > ) > else > if ($a/contact = $v2/contact) > then ( > replace value of node $a/contact with $v1/contact, > replace value of node $v2/contact with $v1/contact > ) > else ( > insert node > <fail> > <arch>{ $a }</arch> > <v1>{ $v1 }</v1> > <v2>{ $v2 }</v2> > </fail> > into doc("log.xml")/log > ) > , > > replace value of node doc("archive.xml")/*/last-synch-time > with current-dateTime() >
Works. Thanks! - Jerome (In reply to comment #4) > I think this fixes the Use Case "R" Q4: > > > let $user := doc("users.xml")/users/user_tuple[name="Annabel Lee"] return > if ($user/rating) > then replace value of node $user/rating with "B" > else insert node <rating>B</rating> into $user >
Yes, I agree it's not really a bug. I just think the text can easily been read as saying: "it's appearing last but that's not enforced by the semantics", which I think is what the comment was about. - Jerome (In reply to comment #5) > [quote]Q4: The note says that "as last into" should be used if position is > important, but the expected result shows that the "radio" element > is inserted as the first child of "car", not as the last one.[/quote] > > But that's the point. I show a query that doesn't specify position, and it > winds up first, which might be unexpected. In subsequent text, I then say that > you can put it in a particular position, e.g. by specifying "as last". > > I don't think this is a bug. >
Thanks. I think there is still a problem. The local function is defined as taking elements of type env:Envelop as input, but it's passed an env:Body. You may want to remove '//env:Body' in the function call. - Jerome (In reply to comment #2) > I believe this fixes the errors in Use Case "SOAP": > > <pre> > declare namespace env="http://www.w3.org/2003/05/soap-envelope"; declare > namespace m="http://travelcompany.example.org/reservation"; declare > namespace n="http://mycompany.example.com/employees"; declare namespace > p="http://travelcompany.example.org/reservation/travel"; (: A clarification > is needed only if there are no : airports or more than one for a given city. > If : there is precisely one, there is no need to : ask for information on > that city. :) declare function local:airportChoices($city as xs:string) { > let $airports := collection("airports")[CITY = $city] return if > (count($airports) = 0) then <error> No airports found for > {$city}!</error> else if (count($airports) > 1) then > <airportChoices> { for $c in $airports/CODE return > (string( $c ), " ") } </airportChoices> else () }; (: Make > sure that each airport is unambiguous. If there is : more than one airport > for a city, ask for clarification. : : The primer only shows the error > condition, so it is not : clear what to do if there are no errors. Here, we > simply : return the airports in the itinerary. :) declare function > local:airports($in as element(env:Envelope)) { let $departureDeparting := > $in//p:departure/p:departing let $departureDepartingAirports := > collection("airports")[CITY = $departureDeparting] let $departureArriving > := $in//p:departure/p:arriving let $departureArrivingAirports := > collection("airports")[CITY = $departureArriving] let $returnDeparting > := $in//p:return/p:departing let $returnDepartingAirports := > collection("airports")[CITY = $returnDeparting] let $returnArriving := > $in//p:return/p:arriving let $returnArrivingAirports := > collection("airports")[CITY = $returnArriving] return if ( > count($departureDepartingAirports)=0 or > count($departureDepartingAirports)>1 or > count($departureArrivingAirports)=0 or > count($departureArrivingAirports)>1 or > count($returnDepartingAirports)=0 or > count($returnDepartingAirports)>1 or > count($returnArrivingAirports)=0 or > count($returnArrivingAirports)>1 ) then > <p:itineraryClarification> <p:departure> > <p:departing> { local:airportChoices($departureDeparting) } > </p:departing> <p:arriving> { > local:airportChoices($departureArriving) } </p:arriving> > </p:departure> <p:return> <p:departing> > { local:airportChoices($returnDeparting) } </p:departing> > <p:arriving> { > local:airportChoices($returnArriving) } </p:arriving> > </p:return> </p:itineraryClarification> else > <p:itinerary> <p:departure> > <p:departing>{$departureDeparting}</p:departing> > <p:arriving>{$departureArriving}</p:arriving> </p:departure> > <p:return> <p:departing>{$returnDeparting}</p:departing> > <p:arriving>{$returnArriving}</p:arriving> </p:return> > </p:itinerary> }; declare variable $msg external; copy $out := > $msg/env:Envelope modify ( replace value of node $out//m:dateAndTime > with fn:current-dateTime(), replace node $out//env:Body with > <env:Body> { local:airports($out//env:Body) } </env:Body> ) > return $out > </pre> >
(In reply to comment #11) > Thanks. I think there is still a problem. The local function is defined as > taking > elements of type env:Envelop as input, but it's passed an env:Body. > > You may want to remove '//env:Body' in the function call. Ooops - you're right - fixing that now. Thanks! Jonathan
Works! Thanks, - Jerome (In reply to comment #6) > [quote]Q3: Neither solution 1, nor solution 3 lead to the expected result. > Solution 1 doesn't delete piston, window and lock. > The recursive function is solution 2 is also incorrect, as it > deletes in "part-tree.xml" at the first call and in "part-list.xml" > at subsequent calls.[/quote] > > I believe this is correct for solution 1: > > > for $pt in doc("part-tree.xml")//part[@name="car"]//part, > $pl in doc("part-list.xml")//part > where $pt/@partid eq $pl/@partid > return > delete nodes $pl > > I believe this is correct for solution 2: > > declare updating function > local:delete-subtree($p as element(part)) > { > for $child in doc("part-list.xml")//part > where $p/@partid eq $child/@partof > return ( > delete nodes $child, > local:delete-subtree($child) > ) > }; > > for $p in doc("part-list.xml")//part[@name="car"] > return > local:delete-subtree($p) >