Ranjith Reddy
Ranjith Reddy

Reputation: 129

Xquery setting global variable inside a if condition

We have below Input

<root>
<Input>1010</Input>
<ReadInput>a123c123</ReadInput>
</root>

Input tag indicates there must be two elements in output (AAAA and CCCC) which is indicated by 1 and each has 4 characters.

1 - AAAA is ON
0 - BBBB is OFF
1 - CCCC is ON
0  - DDDD is OFF 

Hence the below Ouput:

Output

<Result>
<AAAA>a123</AAAA>
<CCCC>b123</CCCC>
</Result>

Now the problem is I have all 26 elements upto Z. So when creating Z element we need to check for availability of all the elements before it with '1' as their index in tag. Can this be achieved in xquery. Further, we are looking for a way to set global variable inside a function to achieve this and looks lilke its not possible in xquery.

Upvotes: 0

Views: 1064

Answers (2)

Michael Kay
Michael Kay

Reputation: 163458

I think this is best tackled with a recursive function

declare function local:f($root as element(root), $i as xs:integer, $j as xs:integer) {
  if (string-length($root/Input) le $i)
  then if ((substring($root/Input, $i, 1) eq '1')
       then (element { local:tag($i) }
                     { substring($root/ReadInput, $j, 4 },
             local:f($root, $i+1, $j+4))
       else local:f($root, $i+1, $j)
  else ()
};

declare function local:tag($i as xs:integer) {
  let $n := format-integer($i, 'A')
  return $n||$n||$n||$n
};

local:f(root, 1, 1) 

Upvotes: 1

Martin Honnen
Martin Honnen

Reputation: 167706

With XQuery 3 and the analyze-string function you could break up the data into sequences and use

<Result>
{
let 
  $bits as xs:integer* := analyze-string(root/Input, '[01]')//*:match!xs:integer(.),
  $values as xs:string* := analyze-string(root/ReadInput, '.{4}')//*:match!string(),
  $element-names as xs:string* := (string-to-codepoints('A') to string-to-codepoints('Z'))!codepoints-to-string(.)!(. || . || . || .),
  $positions := $bits[. = 1]!index-of($bits, .),
  $output-elements as xs:string* := $element-names[position() = $positions]
return 
  for $n at $pos in $output-elements
  return element {$n} { $values[$pos] }
}
</Result>

http://xqueryfiddle.liberty-development.net/eiQZDba

As an alternative you could use substring:

<Result>
{
let 
  $bitString as xs:string := root/Input/string(),
  $bits as xs:integer* := for $p in 1 to string-length($bitString) return xs:integer(substring($bitString, $p, 1)),
  $valueString as xs:string := root/ReadInput/string(),
  $values as xs:string* := for $p in 0 to count($bits[. = 1]) - 1 return substring($valueString, 1 + $p * 4, 4),
  $element-names as xs:string* := (string-to-codepoints('A') to string-to-codepoints('Z'))!codepoints-to-string(.)!concat(., ., ., .),
  $positions := $bits[. = 1]!index-of($bits, .),
  $output-elements as xs:string* := $element-names[position() = $positions]
return 
  for $n at $pos in $output-elements
  return element {$n} { $values[$pos] }
}
</Result>

http://xqueryfiddle.liberty-development.net/eiQZDba/1

Upvotes: 1

Related Questions