Changing element content before return

Hi XQUERIES,
I need to do an XQUERY that finds a number of documents with around 100 element + attributes.
Some of the attributes need to be looked up using a join to another doc, and the value from the join should the become the element content.

this:




should become

some text from join

As I need to return all elements and attributes I use the “magical” syntax

for $q …
return { $q/@*,$q/node()}}

to return the full document.

I had imagined that I could use some kind of “let” syntax to assign a value to a specific element. But after spending some hours consulting documentation from various sources I’m about to give up :wink:

Finn

Finn,

sory, but I did not get what you want to achieve. Could you please give a simple example (or the query in the syntax that you have tried)

regards

Harald

Hi Harald,
The Xquery below is an example of the general query hver a number of document are retrieved and positioning info is added as new X and Y attributes at the root level “”.
But me qeustion is then how do I add element content to a handfull of already existing elements, without having to (re)create ALL element in the return clause.

  • I’m still hoping to persuade the developer to change the format, but currently the schema has unlimited occurrences of the element in question right below the root-level.

{
let $startpos := 5
let $resultsize := 10
{-- First determine total number of hits --}
let $x := count (for $b in input()/J
where tf:containsText($b/F,“deltid”) and tf:containsText($b/F,“ansvarsbevidst”) return $b)

{-- Make a resultset in $items with startpos, resultsize --}
let $items := ((for $q in input()/J
where tf:containsText($q/F,“deltid”) and tf:containsText($q/F,“ansvarsbevidst”)
return $q) [position() >= $startpos and position() < $startpos + $resultsize] )

{-- Iterate through resultset and return documents and add x and y as attributes to element --}
for $i in 1 to count($items)

{-- And this is where I would like to set the text-content of the element JOBTYPE
somthing like:
let $items[$i]/JOBTYPE := ‘TEXT FROM JOIN’ --}

return {$items[$i]/@*,$items[$i]/node()}}

}

Hi Finn,

the curly braces between the opening and closing the J element tags contain
what you want to be the attributes and children of this tag to be. In addition
to the item element’s attributes and children just also add the new children
you want J to contain, i.e. {‘TEXT FROM JOIN’}
preferably at the end with an additional preceding comma.

Regards,
Juliane.

PS: Your query might perform (and look) better, if you just iterate through
the result set without using $i, i.e. say for $item in $items instead of for $i in…

PPS: It might still be better to compute the totlal number of hits first and
afterwards count and restrict:
let $hits := …
let $x := count($hits)
let $items := $hits[position() >= …]

Hi Finn,

if sequence does not matter, you can do as follows:


let $startpos := 2 
let $resultsize := 2
{-- First determine total number of hits --} 
let $matches:= for $b in input()/J 
                 where tf:containsText($b/F,"deltid") and tf:containsText($b/F,"ansvarsbevidst") 
                 return $b
let $x := count ($matches) 
{-- Make a resultset in $items with startpos, resultsize --} 
let $items := ($matches)[position() >= $startpos and position() < $startpos + $resultsize]  
{-- Iterate through resultset and return documents and add x and y as attributes to element --} 
for $i in 1 to count($items) 
{-- And this is where I would like to set the text-content of the element JOBTYPE somthing like: 
let $items[$i]/JOBTYPE := 'TEXT FROM JOIN' --} 
return <J>{$items[$i]/@*,$items[$i]/node() except $items[$i]/JOBTYPE,<JOBTYPE>TEXT FROM JOIN</JOBTYPE> }</J>

if sequence matters, try:


let $startpos := 2 
let $resultsize := 2
{-- First determine total number of hits --} 
let $matches:= for $b in input()/J 
                 where tf:containsText($b/F,"deltid") and tf:containsText($b/F,"ansvarsbevidst") 
                 return $b
let $x := count ($matches) 
{-- Make a resultset in $items with startpos, resultsize --} 
let $items := ($matches)[position() >= $startpos and position() < $startpos + $resultsize]  
{-- Iterate through resultset and return documents and add x and y as attributes to element --} 
for $i in 1 to count($items) 
{-- And this is where I would like to set the text-content of the element JOBTYPE somthing like: 
let $items[$i]/JOBTYPE := 'TEXT FROM JOIN' --} 
return <J>{$items[$i]/@*,for $n in $items[$i]/node() return if (local-name($n)="JOBTYPE") then <JOBTYPE>TEXT FROM JOIN</JOBTYPE> else $n}</J>

or - even more generic



let $startpos := 2 
let $resultsize := 2
{-- First determine total number of hits --} 
let $matches:= for $b in input()/J 
                 where tf:containsText($b/F,"deltid") and tf:containsText($b/F,"ansvarsbevidst") 
                 return $b
let $x := count ($matches) 
{-- Make a resultset in $items with startpos, resultsize --} 
let $items := ($matches)[position() >= $startpos and position() < $startpos + $resultsize]  
{-- Iterate through resultset and return documents and add x and y as attributes to element --} 
for $i in 1 to count($items) 
{-- And this is where I would like to set the text-content of the element JOBTYPE somthing like: 
let $items[$i]/JOBTYPE := 'TEXT FROM JOIN' --} 
return element {node-name($items[$i])} {$items[$i]/@*,for $n in $items[$i]/node() return if (local-name($n)="JOBTYPE") then element {local-name($n)} {"TEXT FROM JOIN"} else $n}

Regards

Harald

Overwhelming - two replies within minutes ! :wink:

To Juliane
I’ll experiment with your ideas, but I guess postprocessing might come in the way of your optimization :frowning:

To Harald
Exactly what I needed - just an additional question.
What is the syntax for the “except” or “if” if there are more than one element that should be changed ? (i.e. both and )

Finn

Hi Finn,

you can just nest the ifs:
if (element1) then…
else if (element2) then…
else…

except takes a sequence: $matches except (node1, node2, …)

regards

Harald