FME Transformers: 2024.2

XQuery Examples

Here are some sample XQueries using the following XML document:

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.0">
<Response>
<name>-122.857000,49.138000</name>
<Placemark id="p1">
<address>7455 132 St, Surrey, BC, Canada</address>
<Point><coordinates>-122.856695,49.137818,0</coordinates></Point>
</Placemark>
</Response>
</kml>

Since the top-level node contains the namespace declaration 'xmlns', the namespace must be declared in the query and it must be used to specify every element. The query:

declare namespace x='http://earth.google.com/kml/2.0';
/x:kml

Results in:

`_result' has value '<kml xmlns="http://earth.google.com/kml/2.0"><Response><name>-122.857000,49.138000</name><Placemark id="p1"><address>7455 132 St, Surrey, BC, Canada</address><Point><coordinates>-122.856695,49.137818,0</coordinates></Point></Placemark></Response></kml>'

If the top-level node had no namespace attribute (that is, '<kml>'), then the following XPath expression would produce the same result:

/kml

The XPath expression below will return the full XML string regardless of namespace:

/*

Similarly, the depth of the query can be specified using the wildcard '*':

/*/*/*/*/*
`_result' has value `<coordinates xmlns="http://earth.google.com/kml/2.0">-122.856695,49.137818,0</coordinates>'

An XPath expression beginning with '//' will specify that the search start from any node that matches the element that directly follows.

declare namespace x='http://earth.google.com/kml/2.0';
//x:Point
`_result' has value `<Point xmlns="http://earth.google.com/kml/2.0"><coordinates>-122.856695,49.137818,0</coordinates></Point>'

The following query will match all nodes:

//*

Seven features are returned, containing as the result the values of the kml, Response, name, Placemark, address, Point, and coordinates nodes.

To retrieve the value of an attribute, use the following syntax:

declare namespace x='http://earth.google.com/kml/2.0';
string(//x:Placemark/@id)
`_result' has value `p1'

In all of the above examples, the query has been a simple XPath expression. XQuery also supports more complex operations using the 'for', 'let', 'where', 'order by', and 'return' keywords. The XML source may also be specified in the query using the 'doc("file.xml")' function.

declare namespace x='http://earth.google.com/kml/2.0';
for $node in doc("address.xml")//x:Placemark
where $node/@id = 'p1'
return concat( $node/address/text(),
" is located at " ,
$node/Point/coordinates/text() )
`_result' has value `7455 132 St, Surrey, BC, Canada is located at -122.856695,49.137818,0'

Here are some sample XQuery updates using the following XML document:

<parcels>
<parcel>
<parcelLocation>
<parcelBounds>
<topLeft>49.37238665158286 -123.17986965179443 </topLeft>
<bottomRight> 49.37064012679701 -123.17738056182861</bottomRight>
</parcelBounds>
<parcelRef>49.3715203830451 -123.17888259887695 </parcelRef>
</parcelLocation>
<parcelOwner>
<owner>
<name>Alice Wight</name>
<address type="mail">1037 West 36 Ave, Vancouver, BC, CANADA</address>
<address type="email">alice.wight@example.com</address>
</owner>
</parcelOwner>
</parcel>
</parcels>

The following query will re-name the bounding elements everywhere they occur in the document:

rename node //topLeft as "upperLeft",
rename node //bottomRight as "lowerRight"

In the result, the lines:

<topLeft>49.37238665158286 -123.17986965179443 </topLeft>
<bottomRight> 49.37064012679701 -123.17738056182861</bottomRight>

Are replaced with:

<upperLeft>49.37238665158286 -123.17986965179443 </upperLeft>
<lowerRight> 49.37064012679701 -123.17738056182861</lowerRight>

Suppose that a format that uses a homespun envelope is changed to use the gml envelope. Here is an XQuery to make that modification:

declare namespace gml = "http://www.opengis.net/gml" ;
for $node in //parcelBounds
return (
delete node $node,
insert node <gml:envelope>
<gml:pos>{$node/topLeft/text()}</gml:pos>
<gml:pos>{$node/bottomRight/text()}</gml:pos>
</gml:envelope> as first into $node/..
)

In the result, the lines:

<parcelBounds>
<topLeft>49.37238665158286 -123.17986965179443 </topLeft>
<bottomRight> 49.37064012679701 -123.17738056182861</bottomRight>
</parcelBounds>

Are replaced with:

<gml:envelope xmlns:gml="http://www.opengis.net/gml">
<gml:pos>49.37238665158286 -123.17986965179443 </gml:pos>
<gml:pos> 49.37064012679701 -123.17738056182861</gml:pos>
</gml:envelope>

Suppose instead that Alice Wight has sold her parcel to Henry Cooper. The following query will update the relevant information in the file "parcels.xml" (which contains the original XML sample):

for $node in doc("parcels.xml")//owner where $node/name = "Alice Wight"
return (
replace value of node $node/name with "Henry Cooper",
replace value of node $node/address[@type='mail']
with "2062 West 38 Ave, Vancouver, BC, CANADA",
replace value of node $node/address[@type='email']
with "henry.cooper@example.com"
)

In the file "parcels.xml", these two lines:

<owner>
<name>Alice Wight</name>
<address type="mail">1037 West 36 Ave, Vancouver, BC, CANADA</address>
<address type="email">alice.wight@example.com</address>
</owner>

Will be updated to contain the following:

<owner>
<name>Henry Cooper</name>
<address type="mail">2062 West 38 Ave, Vancouver, BC, CANADA</address>
<address type="email">henry.cooper@example.com</address>
</owner>