My XML document contains a record of the movement of an object. The XML document consists of a series of observations. Each observation contains the lat/long location of the object, the lat/long of the observing sensor, and a date/time stamp.
<Track-History>
<Track-ID>XYZ</Track-ID>
<Observation>
<Target-Latitude>10.3</Target-Latitude>
<Target-Longitude>20.8</Target-Longitude>
<Observer-Latitude>40.0</Observer-Latitude>
<Observer-Longitude>50.0</Observer-Longitude>
<DateTime>20230202T071700.00</DateTime>
</Observation>
<Observation>
<Target-Latitude>15.1</Target-Latitude>
<Target-Longitude>25.2</Target-Longitude>
<Observer-Latitude>40.0</Observer-Latitude>
<Observer-Longitude>50.0</Observer-Longitude>
<DateTime>20230202T071800.00</DateTime>
</Observation>
</Track-History>
I want to fuzz the locations of the object by rounding the decimal lat and long values. So I created this updating function:
declare updating function f:fuzzPoint($lat as element(), $long as element())
{
replace node $lat with
element {name($lat)} {round(number(data($lat)))},
replace node $long with
element {name($long)} {round(number(data($long)))}
};
When I invoke that function:
{f:fuzzPoint($obs/Target-Latitude, $obs/Target-Longitude)}
I get this error message:
If any subexpression is updating, then all must be updating
Oxygen XML gives a red squiggly line under the function arguments, so apparently the arguments must be updating. Yes? If so, how to make the arguments updating?
Below is my complete XQuery Update program.
declare namespace f = "function";
declare variable $Track-History := doc('Track-History.xml');
declare variable $track-history-points := (for $i in $Track-History//Observation return [$i/Target-Latitude, $i/Target-Longitude]);
declare variable $AOR := (); (: should be a sequence of points, fake it for now :)
declare function f:isInside($points, $polygon) as xs:boolean
{
true()
};
declare updating function f:fuzzPoint($lat as element(), $long as element())
{
replace node $lat with
element {name($lat)} {round(number(data($lat)))},
replace node $long with
element {name($long)} {round(number(data($long)))}
};
if (f:isInside($track-history-points, $AOR)) then
for $obs in $Track-History//Observation return
replace node $obs with
<Observation>
{f:fuzzPoint($obs/Target-Latitude, $obs/Target-Longitude)}
{$obs/Observer-Latitude}
{$obs/Observer-Longitude}
{$obs/DateTime}
</Observation>
else
replace node $Track-History/* with
<Track-History/>
Inside an update expression – replace node $obs with ...
– it’s not allowed to perform other updates. The code works if you modify f:fuzzPoint
such that it returns the new element nodes:
declare function f:fuzzPoint($lat as element(), $long as element()) {
element { name($lat) } { round(number(data($lat))) },
element { name($long) } { round(number(data($long))) }
};
The updating
keyword in the function declaration makes sense if you move the update operation inside the function body:
declare updating function f:replace($obs as element()) {
let $lat := $obs/Target-Latitude
let $long := $obs/Target-Longitude
return replace node $obs with <Observation>{
element { name($lat) } { round(number(data($lat))) },
element { name($long) } { round(number(data($long))) },
$obs/Observer-Latitude,
$obs/Observer-Longitude,
$obs/DateTime
}</Observation>
};
if (f:isInside($track-history-points, $AOR)) then
for $obs in $Track-History//Observation return f:replace($obs)
else
replace node $Track-History/* with
<Track-History/>