Friday, 13 February 2009

Basic Custom functions

The heart and soul of XQuery relies on an intercut network of functions distributed throughout library modules, offering reusable functionality, rivaling most procedural languages.

If you're familiar with XSLT 2, you probably had the chance to use functions in a very similar format to the way functions are implemented in XQuery.

Ultimately the main goal of functions is to group functionality in smaller portions, facilitating reusability of code. When you call a function you can pass values known as parameters to its local scope. Functions can either return something, or can return the equivalent of void in other languages in the format of an empty sequence.


declare function local:myFunction() as xs:string
{"myFunction"};

local:myfunction()


The above code will return the string "myFunction"

The declare function bit is self explanetory, local:myFunction is the namespace and function name respectively. The local namespace is a reserved namespace prefix built into XQuery, and traditionally used for locally declared functions (I'll probably write another blog explaining modules and external custom functions).

The (), represents an empty sequence of parameters. In this example no parameters are required by the function signature.

"as xs:string" is the returned value type, in this case a simple string. You don't need to strongly type the return type of a function, but in my opinion, it keeps the code clean and forces run time cast exceptions, if the values returned by a function aren't what you're expecting, making debugging much easier.

Ok, lets look at a more complex example:

XML Input

<?xml version="1.0" encoding="utf-8"?>
<geo:location xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#">
<geo:lat>51.667795</geo:lat>
<geo:long>0.040683</geo:long>
</geo:location>


XQuery

xquery version "1.0";

declare namespace geo="http://www.w3.org/2003/01/geo/wgs84_pos#";
declare namespace georss="http://www.georss.org/georss";

declare function local:get-georss($_latitude as xs:float, $_longitude as xs:float) as element(georss:point)
{
element georss:point {fn:concat($_latitude, " ", $_longitude)}
};


<rss version="2.0" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:georss="http://www.georss.org/georss">
<channel>
<title>Some RSS feed with geodata</title>
<link>http://www.foo.com/locations</link>
<description>Geo RSS location info</description>
<pubDate>Sat, 7 Feb 2009 22:24:09 -0800</pubDate>
<lastBuildDate>Sat, 7 Feb 2009 22:24:09 -0800</lastBuildDate>
<item>
<title>High Beach</title>
<link>http://www.foo.com/location?lat={fn:data(/geo:location/geo:lat)}&long={fn:data(/geo:location/geo:long)}</link>
<description>High Beach, Epping Forest, London, UK</description>
<pubDate>Sat, 7 Feb 2009 22:24:09 -0800</pubDate>
{
(
local:get-georss(
xs:float(/geo:location/geo:lat),
xs:float(/geo:location/geo:long)
),
/geo:location/geo:lat,
/geo:location/geo:long
)
}
</item>
</channel>
</rss>


returns

<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:georss="http://www.georss.org/georss"
xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
version="2.0">
<channel>
<title>Some RSS feed with geodata</title>
<link>http://www.foo.com/locations</link>
<description>Geo RSS location info</description>
<pubDate>Sat, 7 Feb 2009 22:24:09 -0800</pubDate>
<lastBuildDate>Sat, 7 Feb 2009 22:24:09 -0800</lastBuildDate>
<item>
<title>High Beach</title>
<link>http://www.foo.com/location?lat=51.667795&long=0.040683</link>
<description>High Beach, Epping Forest, London, UK</description>
<pubDate>Sat, 7 Feb 2009 22:24:09 -0800</pubDate>
<georss:point>51.667793 0.040683</georss:point>
<geo:lat>51.667795</geo:lat>
<geo:long>0.040683</geo:long>
</item>
</channel>
</rss>


This time the function local:get-georss() accepts two parameters, the first parameter an xs:float representing the latitude, and the second, again an xs:float representing the longitude. The function local:get-georss() must return a georss:point, element.
The body of the function first creates the element georss:point, then concatenates the latitude, and longitude values as it's text node separated by an empty space character.

To call local:get-georss(), you'll notice the values passed have been converted to the data types required for each parameter, in this case xs:float. When the query invokes the following function call to local:get-georss(), it returns <georss:point>51.667793 0.040683</georss:point>


local:get-georss(
xs:float(/geo:location/geo:lat),
xs:float(/geo:location/geo:long)
)

1 comment:

  1. Hi Melo,
    I have one basic doubt in XQuery as i am new to it. Do we need to have a back end server to run a XQuery program or just the browser will do as like XSLT. If it requires some software to run, then what are those softwares?

    Regards,
    Nishanth.C

    ReplyDelete