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
Related
How to call a custom xquery function in exist-db using the REST API ?
Is it possible to have more than 1 function in the xquery file ?
declare function local:toto() as node() {
return doc("/db/ProjetXML/alice.xml")/raweb/identification/projectName)
};
declare function local:pomme() as node() {
return doc("/db/ProjetXML/carmen.xml")/raweb/identification/projectSize);
};
If I call it using :
http://localhost:8080/exist/rest/db/ProjetXML/orange.xqy?_query=local:toto()
I get the following error :
err:XPST0017 Call to undeclared function: local:toto [at line 1, column 1, source: local:toto()]
Your help is appreciated.
You have syntax errors in your XQuery:
You have two functions named local:toto(). Each function must have a distinct name.
There is no semicolon following the function definition, i.e. } should be };.
Also you should remove the return expression, as there is no preceding binding.
Another option would be to parameterize the input file, e.g.:
import module namespace request="http://exist-db.org/xquery/request";
declare function local:toto($name as xs:string) as node() {
let $doc :=
if($name eq "carmen")then
doc("/db/ProjetXML/carmen.xml")
else
doc("/db/ProjetXML/alice.xml")
return
$doc/raweb/identification/projectName);
};
local:toto(request:get-parameter("name", "alice"))
You can then call this via the REST Server using a URL like:
http://localhost:8080/exist/rest/db/ProjetXML/orange.xqy?name=carmen
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'
I have a content.xml modelled as below
<root>
<childnode>
Some text here
</childnode>
</root>
I am trying to remove the <childnode> and update the content.xml with only the value of it
so the output looks like
<root>
Some Text here
</root>
I wrote a function to perform this but anytime I run it it gives me error as "unexpected token: modify". I was thinking of a way to accomplish this without using functx functions.
xquery version "1.0";
declare namespace request="http://exist-db.org/xquery/request";
declare namespace file="http://exist-db.org/xquery/file";
declare namespace system="http://exist-db.org/xquery/system";
declare namespace util="http://exist-db.org/xquery/util";
declare namespace response="http://exist-db.org/xquery/response";
declare function local:contentUpdate() {
let $root := collection('/lib/repository/content')//root/childNode
let $rmChild := for $child in $root
modify
(
return rename node $child as ''
)
};
local:updateTitle()
Thanks in advance
There are multiple problems with your query:
Updating functions must be declared as updating.
You're calling another function than you defined (probably you didn't notice as there still have been syntax errors).
Rename node expects some element (or processing instruction, attribute) as target, the empty string is not allowed.
At least BaseX doesn't allow updating statements when defining code as XQuery 1.0. Maybe exist doesn't care about this, try adding it if you need to know.
You do not want to rename, but replace all <childnode />s with its contents, use replace node.
This code fixes all these problems:
declare updating function local:contentUpdate() {
let $root := collection('/lib/repository/content')
return
for $i in $root//childnode
return
replace node $i with $i/data()
};
local:contentUpdate()
eXist-db's XQuery Update syntax is documented at http://exist-db.org/exist/update_ext.xml. Note that this syntax predates the release of the XQuery Update Facility 1.0, so the syntax is different and remains unique to eXist-db.
The way to do what you want in eXist-db is as follows:
xquery version "1.0";
declare function local:contentUpdate() {
let $root := doc('/db/lib/repository/content/content.xml')/root
return
update value $root with $root/string()
};
local:contentUpdate()
The primary changes, compared to your original code, are:
Inserted the eXist-db syntax for your update
Prepended '/db' to your collection name, as /db is the root of the database in eXist-db; replaced the collection() call with a doc() call, since you stated you were operating on a single file, content.xml
Changed //root to /root, since "root" is the root element, so the // (descendant-or-self) axis is extraneous
Replaced updateTitle() with the actual name of the function, contentUpdate
Removed the extraneous namespace declarations
For more on why I used $root/string(), see http://community.marklogic.com/blog/text-is-a-code-smell.
let us consider a sample code
declare function local:topic(){
let $forumUrl := "http://www.abc.com"
for $topic in $rootNode//h:td[#class="alt1Active"]//h:a
return
<page>{concat($forumUrl, $topic/#href, '')}</page>
};
declare function local:thread(){
let $forumUrl := "http://www.abc.com"
for $thread in $rootNode//h:td[#class="alt2"]//h:a
return
<thread>{concat(forumUrl, $thread/#href, '')}</thread>
};
Instead of repeating "$forumUrl" , can i pass any arguments in this code.If its possible please assist me.
this is sure possible, you may either pass it in or declare it as a "global" variable:
Declared Variable:
declare variable $forumUrl := "http://www.abc.com";
declare variable $rootNode := doc('abc');
declare function local:topic(){
for $topic in $rootNode//td[#class="alt1Active"]//a
return
<page>{concat($forumUrl, $topic/#href, '')}</page>
};
declare function local:thread(){
for $thread in $rootNode//td[#class="alt2"]//a
return
<thread>{concat($forumUrl, $thread/#href, '')}</thread>
};
Or you pass the URL as an argument:
declare variable $rootNode := doc('abc');
declare function local:topic($forumUrl){
for $topic in $rootNode//td[#class="alt1Active"]//a
return
<page>{concat($forumUrl, $topic/#href, '')}</page>
};
declare function local:thread($forumUrl){
for $thread in $rootNode//td[#class="alt2"]//a
return
<thread>{concat($forumUrl, $thread/#href, '')}</thread>
};
local:topic("http://www.abc.de")
N.B. I stripped the 'h:' namespace from your example and added the $rootNode variable.
Hope this helped.
In general arguments to XQuery function may be specified as followed:
local:foo($arg1 as type) as type
where type may be for example:
xs:string a string
xs:string+ a sequence of at least one string(s)
xs:string* an arbitrary number of strings
xs:string? a sequence of length zero or one of strings
Functions may have as many arguments as you wish, the type for the arguments may be omitted.
A functions return value may as well be typed, in the context of your example the signature might be:
declare function local:thread($forumUrl as xs:string) as element(thread)+
defining that local:thread accepts exactly one string and returns a non-empty sequence of thread elements.
Michael
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.