Passing arguments in Xquery - xquery

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

Related

Call custom xquery function in eXist-db using url

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

What is the syntax for defining a type when parameter has a default value?

How do I define the type of the config parameter given that it has a default value?
function (config = {}) {};
function f(config: Object = {}) {}
Or, more generally:
function f(p: T = v) {}
where T is a type, and v is a value of type T.
Interestingly, the type of function f is (p?: T): void. That is, Flow understands that providing a default value makes the parameter optional. You don't need to explicitly make the parameter type optional—although it doesn't hurt.
When writing declare function statement in a .js.flow file, you can't include the default value; it will cause an error. So you must explicitly declare that the parameter is optional:
declare function f(p?: T): void;
Flow types and default arguments in fat-arrow functions work similarly.
Given a function called foo which takes argument bar, you specify the type immediately after the argument with a colon, and then set its default value with the assignment (=) operator. Finally, immediately after closing the parentheses, you define the return value's type with another colon.
foo = (bar: string = 'baz'): string => bar;
foo(); // 'baz'

How to dynamically create a search query based on a set of quoted strings in MarkLogic

I have the following query, where i want to form a string of values from a list and i want to use that comma separated string as an or-query but it does not give any result, however when i return just the concatenated string it gives the exact value needed for the query.
The query is as follows:
xquery version "1.0-ml";
declare namespace html = "http://www.w3.org/1999/xhtml";
declare variable $docURI as xs:string external ;
declare variable $orQuery as xs:string external ;
let $tags :=
<tags>
<tag>"credit"</tag>
<tag>"bank"</tag>
<tag>"private banking"</tag>
</tags>
let $docURI := "/2012-10-22_CSGN.VX_(Citi)_Credit_Suisse_(CSGN.VX)__Model_Update.61198869.xml"
let $orQuery := (string-join($tags/tag, ','))
for $x in cts:search(doc($docURI)/doc/Content/Section/Paragraph, cts:or-query(($orQuery)))
let $r := cts:highlight($x, cts:or-query($orQuery), <b>{$cts:text}</b>)
return <result>{$r}</result>
The exact query that i want to run is :
cts:search(doc($docURI)/doc/Content/Section/Paragraph, cts:or-query(("credit","bank","private banking")))
and when i do
return (string-join($tags/tag, ','))
it gives me exactly what i require
"credit","bank","private banking"
But why does it not return any result in or-query?
The string-join step should not need to be string-join. That passes in a literal string. In xQuery, sequences are your friend.
I think you want to do something like this:
let $tags-to-search := ($tags/tag/text()!replace(., '^"|"$', '') ) (: a sequence of tags :)
cts:search(doc($docURI)/doc/Content/Section/Paragraph, cts:word-query($tags-to-search))
cts:word-query is the default query used for parameter 2 of search if you pass in a string. cts:word query also returns matches for any items in a sequence if presented with that.
https://docs.marklogic.com/cts:word-query
EDIT: Added the replace step for the quotes as suggested by Abel. This is specific to the data as presented by the original question. The overall approach remains the same.
Maybe do you need something like this
let $orQuery := for $tag in $tags/tag return cts:word-query($tag)
I used fn:tokenize instead it worked perfectly for my usecase
its because i was trying to pass these arguments from java using XCC api and it would not return anything with string values
xquery version "1.0-ml";
declare namespace html = "http://www.w3.org/1999/xhtml";
declare variable $docURI as xs:string external ;
declare variable $orQuery as xs:string external ;
let $input := "credit,bank"
let $tokens := fn:tokenize($input, ",")
let $docURI := "2012-11-19 0005.HK (Citi) HSBC Holdings Plc (0005.HK)_ Model Update.61503613.pdf"
for $x in cts:search(fn:doc($docURI), cts:or-query(($tokens)))
let $r := cts:highlight($x, cts:or-query(($tokens)), <b>{$cts:text}</b>)
return <result>{$r}</result>

Calling a function passed as an access type that takes no parameters

Consider a family of functions that take no arguments and return the same type:
function Puzzle1 return Answer_Type;
function Puzzle2 return Answer_Type;
function PuzzleN return Answer_Type;
I'd like to be able to pass those functions to a subprogram and have the subprogram call the function and use the result. I can pass the function to the subprogram by defining an access type:
type Answer_Func_Type is access function return Answer_Type;
However, there doesn't seem to be a way to actually call the passed-in function to get the result:
procedure Print_Result(Label : in String;
Func : in not null Answer_Func_Type;
Expected : in Answer_Type) is
Result : Answer_Type;
begin
Result := Func; -- expected type "Answer_Type", found type "Answer_Func_Type"
Result := Func(); -- invalid syntax for calling a function with no parameters
-- ...
end Print_Result;
Is there a way to do this in Ada without adding a dummy parameter to the functions?
You were trying to use the pointer to a function, not the function itself. Dereference the pointer and all should be well:
procedure Main is
type Answer_Type is new Boolean;
function Puzzle1 return Answer_Type is
begin return True;
end Puzzle1;
type Answer_Func_Type is access function return Answer_Type;
procedure Print_Result(Label : in String;
Func : in not null Answer_Func_Type;
Expected : in Answer_Type) is
Result : Answer_Type;
begin
Result := Func.all; -- You have a pointer, so dereference it!
end Print_Result;
begin
Print_Result ("AAA",Puzzle1'Access, True);
end Main;

Recursive function returning boolean, with a for loop inside

My data is a binary tree, and will check through every child, returning true if it finds the data i want, if not, it keeps looking for it.
In some way i want to return the variable #exists or something.. Well anyone might have a solution for my problem. I was thinking something like this but i couldn't get it to work! (code-snippet)
declare function local:test($id as xs:integer, $topic as xs:integer) as xs:boolean {
let $exists := fn:false()
for $x in ...
return
if .. then
set exists to fn:true()
else
set exists to exists OR local:test($x,$topic)
return #exists in some way
};
This is a case for an XQuery quantified expression. Using that, your function translates to
declare function local:test($id as xs:integer, $topic as xs:integer) as xs:boolean
{
some $x in ...
satisfies
if (..) then
fn:true()
else
local:test($x,$topic)
};
As it was already mentioned XQuery is a functional language. You can't just set variable and return it. Your query can be though rewritten like:
declare function local:test($id as xs:integer, $topic as xs:integer) as xs:boolean {
exists(for $x in ...
where (: here is condition expression on $x :)
return $x)
};
Function exists(Expr) returns true if the value of Expr is not the empty sequence; otherwise, the function returns false.
In this case exists returns true if there is $x which meets specified condition.
You cannot change the values of variables in xquery.
Is your whole function not just this:
declare function local:test($topic as xs:integer) as xs:boolean {
... OR local:test($topic/...)
};

Resources