XQuery concat to the same variable - for-loop

Simple code there-
let $sV2 :=''
for $i in (1 to 2)
let $sV1 := 'test1'
let $sV2 := if (fn:string-length($sV2) != 0) then fn:concat($sV2,'||',$sV1) else ($sV1)
return
<test>{$sV2}</test>
i get the same output
<test>test1</test>
<test>test1</test>
whereas i expect
<test>test1</test>
<test>test1||test1</test>
what am i doing wrong? i tried to debug but why does V2 initialize to null/'' for second iteration.
Note- I have to use xquery 1.0 do to some product limitations.
How do i get the expected output?

XQuery is a functional language. As such, it does not allow you to change the value of a variable once it has been assigned.
There are many other ways to reach the same results, though. Your specific query can e.g. be rewritten as follows:
for $i in 1 to 2
return <test>{
string-join(for $n in 1 to $i return 'test1', '||')
}</test>

Related

XPath expression to compute arithmetics on array of nodes

<record>
<node_1>
<value_1_0>5</value_1_0>
<value_1_1>0</value_1_1>
<value_1_2>10</value_1_2>
<value_1_3>8</value_1_3>
</node_1>
.................................
.................................
<node_63>
<value_63_0>1</value_63_0>
<value_63_1>99</value_63_1>
<value_63_2>53</value_63_2>
<value_63_3>5</value_63_3>
</node_63>
</record>
Problem statement :
How to write efficient XPath expressions for these two cases?
if value is non zero for any node, I need to check if value of that particular subnode for previous and next node are non zero. i.e. if node_50/value_50_0 is non zero, node49/value_49_0 and node51/value_51_0 should also be non zero. Similarly, for rest of the cases.
Next, it should add up the values for alternate nodes. i.e. node_1/value_1_0 + node_3/value_1_0 + ... + node_63/value_1_0. Similarly, for value_1_1,...,value_63_1 and so on.
I am wondering if there is any "for loop" with counter variable provision for each index, so that the XPath expression will be simple for both cases?
pseudo code :
for(i=1; i<64; i++)
for(j=0;j<4;j++)
if (node_i/value_i_j !=0)&& (node_i-1/value_i-1_j !=00)&&(node_i-1/value_i-1_j!=0)
True
else
False
end
end
Using
let $alternate-nodes := /record/*[position() mod 2 = 1]
for $i in (1 to count($alternate-nodes[1]/*))
return
sum($alternate-nodes/*[position() eq $i])
should do to compute the sums. Of course the use of for $i in is only necessary if the element names are really as complicated as in the input where each has one or two index numbers in the name.
For the test for zero or non-zero values should be possible with e.g.
let $nodes := /record/*
for $i in (1 to count($nodes[1]/*))
return every $value in $nodes/*[position() eq $i] satisfies $value != 0
to return a sequence of boolean values.

Understanding for-loop in XQuery to count occurrences in BaseX

I am trying to count the occurrences of an XML structure in BaseX.
declare variable $a := 0;
for $node in db:open("My_DB")/my/xml//path
$a += 1
return $a
When running this, BaseX returns the error: Incomplete FLWOR expression: expecting 'return'.
I know that I can count with this simple function:
count(db:open("My_DB")/my/xml//path)
But there are two reasons zhy I am trying to do this with a for loop:
I have been told by my supervisor that a for loop is faster
In the future I may want to execute more operations per hit (in the for loop)
So the question is: how can I count elements in a for loop with XQuery using BaseX.
As XQuery is a functional language, it’s not possible to reassign other values to a function. However, you can use fold-left to increment values in a loop:
fold-left(db:open("My_DB")/my/xml//path, 0, function($result, $curr) {
$result + 1
})
The execution time for count() depends on the implementation of XQuery. In BaseX, count() is usually much faster than a loop, because it can in many cases be accelerated by lookups in the database statistics.

XQuery: Select a node in the context of a varaible

In order to learn XQuery I tried to run the following XQuery command in BaseX
let $x := doc("test.xq")//h2/following-sibling return $x::h2
I supposed it should be equivalent to
let $x := doc("test.xq")//h2/following-sibling::h2 return $x
But it gives the following error and doesn't work while the second command works
Error:
Stopped at D:/Program Files/BaseX/data/test.xq, 1/66:
[XPST0003] Unexpected end of query: '::h2'.
In general, how can I select some nodes (h2) in the context provided by a variable ($x := doc("test.xq")//h2/following-sibling)
That's not how variables work I'm afraid. It looks like you're trying to treat the variable declaration as a kind of "macro" and expecting its textual definition to be substituted in when the variable is referenced, but in fact XQuery variables are more like local variables in C or Java - the definition expression is evaluated to give a value or sequence and when you refer to the variable you get that value back.
So both the definition and referencing expressions need to be valid expressions in their own right. If you wanted to store the list of all following sibling elements in the variable and then later filter for just the h2 elements you'd need something like
let $x := doc("test.xq")//h2/following-sibling::* return $x[self::h2]
You can't separate the expression at that part, see following-sibling::h2 as one unit. You can do the following instead :
let $x := doc("test.xq")//h2 return $x/following-sibling::h2

XQuery let for let output

I have the following XQuery:
let $a := 0
for $b in (1,2,3)
let $a := $a + 1
return $a+$b
The result I would expect is 2,4,6
However, the result is get is 2,3,4
Why does it produce this result, i.e. why does the value of $a in the for loop stays 1?
Variables in XQuery (and XSLT) are immutable. Therefore, once declared they cannot be reassigned.

xquery- how to obtain min/max value from a set of values that are obtained by subtracting consecutive members from a list

In an xquery expression, I have obtained a set of values within a for-expression, and one value is in a separate variable.
Now, I want to subtract the single value from first value of the list, and then subtract consecutive members of the list from each other-- and in the resulting set of difference values, I want to obtain the min/max values...
The query upto now looks like this--
let $value1:= 1998
let $rows_citations:=
$doc//div[#id="patent_citations"]
/div[#id="patent_citations_v"]
/table[#class="rel_patent"]
/tbody/tr[1]
/following-sibling::tr
for $pos in $rows_citations/position()
let $date2_c := customfn:dateconverter1($rows_citations[$pos]/td[3])
Now the subtraction I want is between first value of date2_c and value 1, and after that between consecutive members of date2_c... And from the resulting list I want the min/max values... How do I go about doing this?
I am esp. confused about creating a new list variable that stores all the differences, esp. when we are already inside a for loop, and are iterating over each value of a list (via variable date2_c)
I. This XQuery 3.0 query (which is also a pure XPath 3.0 expression):
let $pVal := 1,
$vList := (2,4,7,11,16),
$vList2 := ($pVal, subsequence($vList, 1, count($vList)-1)),
$vSubtactedList :=
map-pairs(function($m as xs:integer, $n as xs:integer) as xs:integer
{
$m - $n
},
$vList,
$vList2
)
return
(min($vSubtactedList), max($vSubtactedList))
produces the wanted result the minimum and maximum values from the list of subtractions:
1 5
II. XQuery 1.0 solution:
let $pVal := 1,
$vList := (2,4,7,11,16),
$vList2 := ($pVal, subsequence($vList, 1, count($vList)-1)),
$vSubtactedList :=
for $i in 1 to count($vList)
return
$vList[$i] - $vList2[$i]
return
(min($vSubtactedList), max($vSubtactedList))
This again produces the same correct result:
1 5

Resources