how to use if else in xquery assignment - xquery

I am trying to use a if condition to assign a value to a variable in an xquery. I am not sure how to do this.
This is what I tried:
declare namespace libx='http://libx.org/xml/libx2';
declare namespace atom='http://www.w3.org/2005/Atom';
declare variable $entry_type as xs:string external;
let $libx_node :=
if ($entry_type = 'package' or 'libapp') then
{element {fn:concat("libx:", $entry_type)} {()} }
else if ($entry_type = 'module') then
'<libx:module>
<libx:body>{$module_body}</libx:body>
</libx:module>'
This code throws an [XPST0003] Incomplete 'if' expression error. Can someone help me fix this?
Also, can someone suggest some good tutorials to learn xqueries.
Thanks,
Sony

That's because in XQuery's conditional expression specification else-expression is always required:
[45] IfExpr ::= "if" "(" Expr ")" "then" ExprSingle "else" ExprSingle
So you have to write second else clause (for example, it may return empty sequence):
declare namespace libx='http://libx.org/xml/libx2';
declare namespace atom='http://www.w3.org/2005/Atom';
declare variable $entry_type as xs:string external;
let $libx_node :=
if ($entry_type = ('package','libapp')) then
element {fn:concat("libx:", $entry_type)} {()}
else if ($entry_type = 'module') then
<libx:module>
<libx:body>{$module_body}</libx:body>
</libx:module>
else ()
... (your code here) ...
Some obvious bugs are also fixed:
don't need {} around computed element constructor;
most likely, you want if($entry_type = ('package', 'libapp'))
Concerning XQuery tutorials. The W3CSchools's XQuery Tutorial is a pretty good starting point.

Related

Is it possible to pass a uri parameter with xi:include in exist-db?

I have an exist-db .xql page where I am wrapping three other .xql pages via xi:include:
(:==========
Declare namespaces
==========:)
declare namespace mwjl = "http://minorworksoflydgate.net/mwjl";
declare namespace m = "http://minorworksofjohnlydgate.net/model";
declare namespace tei = "http://www.tei-c.org/ns/1.0";
declare namespace xi = "http://www.w3.org/2001/XInclude";
(:==========
Declare global variables to path
==========:)
declare variable $exist:root as xs:string :=
request:get-parameter("exist:root", "xmldb:exist:///db/apps");
declare variable $exist:controller as xs:string :=
request:get-parameter("exist:controller", "/mwjl-app");
declare variable $path-to-data as xs:string :=
$exist:root || $exist:controller || '/data';
declare variable $docPath as xs:string := "paratext/Lydgate_Main.xml";
(:===
Declare variable
===:)
declare variable $work := doc("/db/apps/mwjl-app/data/" || $docPath);
declare variable $TEI as element(tei:TEI)+ := $work/tei:TEI;
<m:page>
<xi:include href="/db/apps/mwjl-app/modules/header.xql"/>
<xi:include href="/db/apps/mwjl-app/modules/body.xql"/>
<xi:include href="/db/apps/mwjl-app/modules/footer.xql"/>
</m:page>
I would like to pass the variable $docPath to the three xi:include's, but when I format the xi:include as follows (for the footer, for example): <xi:include href="/db/apps/mwjl-app/modules/footer.xql?docPath={$docPath}"/>it ceases to produce results. If put a request:get-parameter statement on the target .xqls and include a fallback (so something like declare variable $docPath as xs:string := request:get-parameter('docPath','fallback') on the target xqls) it generates the fallback fine, so it's obvious to me that the function works. I'm just not forming my href correctly in the xi:include statements in the requesting code. But everything I've read suggests this should be how it's formed and I cannot for the life of me figure out where I'm going wrong. Am I mistaken that this is possible in eXist-db, and if I'm not how do I format the xi:include statement?
I would suggest applying the fn:encode-for-uri() function to the $docPath variable:
<xi:include href="/db/apps/mwjl-app/modules/footer.xql?docPath={encode-for-uri($docPath)}"/>
This function encodes any reserved characters in the supplied string by replacing them with their percent-encoded form. So paratext/Lydgate_Main.xml becomes paratext%2FLydgate_Main.xml.
If this doesn't do the trick (sorry, I haven't tested it), I'd suggest adding logging to the target queries, e.g.:
util:log("INFO", "docPath: " || request:get-parameter('docPath', 'no docPath parameter received'))
... which will be visible in your exist.log file when you next call your main query. (And then, if you could add a comment to this reply with, I'll update my suggestion accordingly.)

user defined function for xquery if else condition

My code is working fine if I don't use function.
declare function local:samlefamily(
$pers as xs:string?) as xs:string?
{
some stuff
};
if (exists(/*/FamilyRec/Child/Link[#Ref = "IN0099"]))
then
for $family in doc("family.xml") /*/FamilyRec
where $family/Child/Link[#Ref = "IN0099"]
return if (local:samlefamily(data($family/HusbFath/Link/#Ref))) then local:samlefamily(data($family/HusbFath/Link/#Ref)) else "na1"
else "na2"
But problem occurs when I tried to define function
declare function local:giveParent($pers as xs:string) as xs:string
{if (exists(/*/FamilyRec/Child/Link[#Ref = $pers]))
then
for $family in doc("gedcom.xml") /*/FamilyRec
where $family/Child/Link[#Ref = $pers]
return if (local:samlefamily(data($family/HusbFath/Link/#Ref))) then local:samlefamily(data($family/HusbFath/Link/#Ref)) else "na1"
else "na2"
};
I am getting error:
Description: Unexpected token "< eof >" in path expression
It is not occurring for passing parameter($pers). Even I use static ("IN0099") parameter to it, same error I am getting.
Can anyone please help? Can't I use If ... else in user defined function? Advanced thanks for your support
You need to have at least one non-function statement in the xquery file, i.e. add anything after the last semicolon
Otherwise your code looks fine

xquery beginner- how to use an if-then-else within a FLWOR statement

I want to extract some content from a web page's XML equivalent, using XQuery.
Here, I want to use if-then-else -- if a specific condition is met, then one value is returned by the xquery expression, otherwise a different value is returned.
This is the expression I have with me--
I am working to extract some content from a web page.
Given below is the Xquery code I am using-- I am using a XQuery library to parse through XML which is obtained by transforming a HTML web page into XML...after that I am extracting some specific content from that XML page...
declare variable $doc as node() external;
let $select_block := $doc//div[#class="randomclass" and contains(.,'MatchingText')]
for $select_link in $select_block/a
for $select_link_url in $select_link/#href
where contains($assignee_link_url,'inassignee')
return data($select_link)
Now how do I use if-then-else within this expression?
I tried to add an if-then immediately after 'return' keyword but I am getting error...
Basically, if some content is found for $select_block above, then data($select_link) should be returned, otherwise the static text 'Missing Value' should be returned.
What is the correct way of using if-then-else with the above xquery expression?
If I understand what you are trying to achieve correctly, then the following should work:
declare variable $doc as node() external;
let $select_block := $doc//div[#class="randomclass" and contains(.,'MatchingText')]
return
if ($select_block) then
for $select_link in $select_block/a
for $select_link_url in $select_link/#href
where contains($select_link_url,'inassignee')
return data($select_link)
else 'Missing Value'
You could simplify things a little bit and eliminate the nested for loops with predicate filters selecting the anchor elements:
declare variable $doc as node() external;
let $select_block := $doc//div[#class="randomclass" and contains(.,'MatchingText')]
return
if ($select_block) then
for $select_link in $select_block/a[#href[contains(., 'inassignee')]]
return data($select_link)
else 'Missing Value'

XQuery - Variables in function definition

Is it possible to declare a variable to be used only inside of function declaration? If so - how to do it?
Variable declaration can only be placed in the prolog of a query, but you can wrap your function code with a FLWOR expression, consisting of a single LET and RETURN clause. An example:
declare function local:func() {
let $var := ...your variable...
return
...your actual code...
};
Hope this helps,
Christian
You can use XQuery Scripting to declare local variables.
declare %a:sequential function local:func() {
variable $var := ....;
...actual code...
}
XQuery Scripting is described in the following tutorial: http://www.zorba-xquery.com/site2/doc/latest/zorba/html/scripting_tutorial.html

XQuery - problem with recursive function

Im new on this project and am going to write, what i thought was a simple thing. A recursive function that writes nested xml elements in x levels (denoted by a variable). So far I have come up with this, but keeps getting a compile error. Please note that i have to generate new xml , not query existing xml:
xquery version "1.0";
declare function local:PrintTest($amount)
{
<test>
{
let $counter := 0
if ($counter <= $amount )
then local:PrintTest($counter)
else return
$counter := $counter +1
}
</test>
};
local:PrintPerson(3)
My error is:
File Untitled1.xquery: XQuery transformation failed
XQuery Execution Error!
Unexpected token - " ($counter <= $amount ) t"
I never understood xquery, and cant quite see why this is not working (is it just me or are there amazingly few resources on the Internet concerning XQuery?)
You have written this function in a procedural manner, XQuery is a functional language.
Each function body can only be a single expression; it looks like you are trying to write statements (which do not exist in XQuery).
Firstly, your let expression must be followed by a return keyword.
return is only used as part of a FLWOR expression, a function always evaluates to a value. As you have written it return is equivalent to /return and so will return a node called return.
The line $counter := $counter + 1 is not valid XQuery at all. You can only set a variable like this with a let expression, and in this case it would create a new variable called counter which replaced the old one, that would be in scope only in the return expression of the variable.
The correct way to do what you are trying to do is to reduce the value of $argument each time the function recurses, and stop when you hit 0.
declare function local:Test($amount)
{
if ($amount == 0)
then ()
else
<test>
{
local:Test($amount - 1)
}
</test>
};
local:Test(3)
Note that I have changed the name of the function to Test. The name "PrintTest" was misleading, as this implies that the function does something (namely, printing). The function in fact just returns a node, it does not do any printing. In a purely functional langauge (which XQuery is quite close to) a function never has any side effects, it merely returns a value (or in this case a node).
The line $counter := $counter + 1 is valid XQuery Scripting.

Resources