Joining sequence and document in XQUERY - xquery

I want to join document and sequence in XQUERY.
I'am trying this code:
let $in_xml :=
<ss>
<s>
<p>2016/2/18/11/protocol13818.xml</p>
<n>service1_1</n>
<d>2016-04-01</d>
</s>
<s>
<p>2016/2/18/15/protocol13819.xml</p>
<n>service_2</n>
<d>2016-04-02</d>
</s>
</ss>
for $a in /version,
$i in $in_xml
where $a/fn:base-uri() = $i/s/p
return <a>{$a//id/value/text()," ", $i//n}</a>
And having this result:
<a>c2e9bb01-acc1-4a64-b39b-f30ef514c5ec <n>service1_1</n>
<n>service_2</n>
</a>
<a>50543b71-48b8-41f6-956e-b444c5ad0abe <n>service1_1</n>
<n>service_2</n>
</a>
Why sequence is not filtered?
I want, that result will be look like this:
<a>c2e9bb01-acc1-4a64-b39b-f30ef514c5ec <n>service1_1</n>
</a>
<a>50543b71-48b8-41f6-956e-b444c5ad0abe <n>service1_2</n>
</a>
How can i do this? Any ideas? Thanks!

When you do $i in $in_xml, you iterate over every element in $in_xml, which is just $in_xml itself, since it is an element and not a sequence. To iterate over all the children of $in_xml, you need to select them:
You want something like
for $a in /version,
$i in $in_xml/s
where $a/fn:base-uri() = $i/p
return <a>{$a//id/value/text()," ", $i/n}</a>

Related

how to sum all of the count items in xquery

My problem is i want to display the count of all genre that is equals to actions
`
<videos genre="action" count="{
for $videos in doc("videos.xml")/result/videos/video
let $count := 0
where $videos/genre ="action"
return count($videos/genre)
}"
`
``
but my result is this
the count is=1 1 1 i want the answer is equal to 3
im expecting a result that is
<videos genre="action" count="3"><video>
You are making it a bit too complicated; try something like:
<videos genre="action" count="{
count(doc("videos.xml")//video[.//genre[.="action"]])
}"/>
or, depending on the struture of you actual videos file, you can use instead
count(//video[.//.="action"])
Those should get you your expected output.

concatenation of one value with multiple values from another xquery

Hej. I am new at XML-query and have some problem finding a way to combine the result of two xquery into one.
Consider the XML:
<programs>
<program id="488">
<editor>Anna</editor>
<channel>132</channel>
<category>5</category>
</program>
<program id="178">
<editor>Olle</editor>
<channel>132</channel>
<category>68</category>
</program>
<program id="179">
<editor>Olle</editor>
<channel>132</channel>
<category>10</category>
</program>
</programs>
I want to extract list of editors along with the categories they have worked on which would be like this:
<li>Anna 5 </li>
<li>Olle 68 10</li>
Here is the xquery code I am using
let $editors :=
for $d in $sr/sr/programs/program
where $d/channel = "132"
return $d/editor
let $cat :=
for $a in $sr/sr/programs/program
where $a/editor = data($editors)
return concat($a/editor ,' ', $a/category)
for $result in distinct-values($cat)
return <li>{string($result)}</li>
Appreciate all the helps!
I would iterate over the distinct list of editors, obtained from an XPath with a predicate to restrict to those with channel equal to 132, and then retrieve a distinct list of categories for those editors with a similar XPath with predicate filter, and then return the HTML with those values:
for $editor in distinct-values($sr/sr/programs/program[channel eq 132]/editor)
let $categories :=
distinct-values($sr/sr/programs/program[channel eq 132 and editor eq $editor]/category)
return <li>{$editor, $categories}</li>

XSLT-style mini transformation in Xquery?

At the moment in Xquery 3.1 (in eXist 4.7) I receive XML fragments that look like the following (from eXist's Lucene full text search):
let $text :=
<tei:text>
<front>
<tei:div>
<tei:listBibl>
<tei:bibl>There is some</tei:bibl>
<tei:bibl>text in certain elements</tei:bibl>
</tei:listBibl>
</tei:div>
<tei:div>
<tei:listBibl>
<tei:bibl>which are subject <exist:match>to</exist:match> a Lucene search</tei:bibl>
<tei:bibl></tei:bibl>
<tei:listBibl>
</tei:div>
<tei:front>
<tei:body>
<tei:p>and often produces</tei:p>
<tei:p>a hit.</tei:p>
<tei:body>
<tei:text>
Currently I have Xquery send this fragment to an XSLT stylesheet in order to transform it into HTML like this:
<td>...elements which are subject <span class="search-hit">to</span> a Lucene search and often p...
Where the stylesheet's job is to return 30 characters of text before and after <exist:match/> and put the content of <exist:match/> into a span. There is only one <exist:match/> per transformation.
This all works fine. However, it's occurred to me that it is a very small job with effectively a single transformation of only one element, the rest being a sort of string-join. I therefore wonder if this can't be done efficiently in Xquery.
In trying to do this, I'm can't seem to find a way to handle the string content up to the <exist:match/> and then the string content after <exist:match/>. My idea is, in pseudo code, to output a result like:
let $textbefore := some function to get the text before <exist:match/>
let $textafter := some function to get text before <exist:match/>
return <td>...{$textbefore}
<span class="search-hit">
{$text//exist:match/text()}
</span> {$textafter}...</td>
Is this even worth doing in Xquery vs the current Xquery -> XSLT pipeline I have?
Many thanks.
I think it can be done as
declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
declare namespace tei = "http://example.com/tei";
declare namespace exist = "http://example.com/exist";
declare option output:method 'html';
let $text :=
<tei:text>
<tei:front>
<tei:div>
<tei:listBibl>
<tei:bibl>There is some</tei:bibl>
<tei:bibl>text in certain elements</tei:bibl>
</tei:listBibl>
</tei:div>
<tei:div>
<tei:listBibl>
<tei:bibl>which are subject <exist:match>to</exist:match> a Lucene search</tei:bibl>
<tei:bibl></tei:bibl>
</tei:listBibl>
</tei:div>
</tei:front>
<tei:body>
<tei:p>and often produces</tei:p>
<tei:p>a hit.</tei:p>
</tei:body>
</tei:text>
,
$match := $text//exist:match,
$text-before-all := normalize-space(string-join($match/preceding::text(), ' ')),
$text-before := substring($text-before-all, string-length($text-before-all) - 30),
$text-after := substring(normalize-space(string-join($match/following::text(), ' ')), 1, 30)
return
<td>...{$text-before}
<span class="search-hit">
{$match/text()}
</span> {$text-after}...</td>
which is not really much of a query in XQuery either but just some XPath selection plus some possibly expensive string joining and extraction on the preceding and following axis.

How to match space in MarkLogic using CTS functions?

I need to search those elements who have space " " in their attributes.
For example:
<unit href="http:xxxx/unit/2 ">
Suppose above code have space in the last for href attribute.
I have done this using FLOWER query. But I need this to be done using CTS functions. Please suggest.
For FLOWER query I have tried this:
let $x := (
for $d in doc()
order by $d//id
return
for $attribute in data($d//#href)
return
if (fn:contains($attribute," ")) then
<td>{(concat( "id = " , $d//id) ,", data =", $attribute)}</td>
else ()
)
return <tr>{$x}</tr>
This is working fine.
For CTS I have tried
let $query :=
cts:element-attribute-value-query(xs:QName("methodology"),
xs:QName("href"),
xs:string(" "),
"wildcarded")
let $search := cts:search(doc(), $query)
return fn:count($search)
Your query is looking for " " to be the entirety of the value of the attribute. If you want to look for attributes that contain a space, then you need to use wildcards. However, since there is no indexing of whitespace except for exact value queries (which are by definition not wildcarded), you are not going to get a lot of index support for that query, so you'll need to run this as a filtered search (which you have in your code above) with a lot of false positives.
You may be better off creating a string range index on the attribute and doing value-match on that.

Xquery group by on 2 tags

Below is the XML part of my data.
<A>
<a><Type>Fruit</Type><Name>Banana</Name></a>
<a><Type>Fruit</Type><Name>Orange</Name></a>
<a><Type>Fruit</Type><Name>Apple</Name></a>
<a><Type>Fruit</Type><Name>Lemon</Name></a>
<a><Type>Cars</Type><Name>Toyota</Name></a>
<a><Type>Cars</Type><Name>Lamborghini</Name></a>
<a><Type>Cars</Type><Name>Renault</Name></a>
</A>
Out put as -
<a>Fruits-Banana,Orange,Apple,Lemon</a>
<a>Cars-Toyota,Lamborghini,Renault</a>
I tried to get the required output by all in vain. I tried 'group by` clause too, but getting errors.
any help?
let $x:=
<A>
<a><Type>Fruit</Type><Name>Banana</Name></a>
<a><Type>Fruit</Type><Name>Orange</Name></a>
<a><Type>Fruit</Type><Name>Apple</Name></a>
<a><Type>Fruit</Type><Name>Lemon</Name></a>
<a><Type>Cars</Type><Name>Toyota</Name></a>
<a><Type>Cars</Type><Name>Lamborghini</Name></a>
<a><Type>Cars</Type><Name>Renault</Name></a>
</A>
for $z in distinct-values($x//a/Type)
let $c := $x//a[Type=$z]/Name
return
<a>{concat($z, "-", string-join($c, ","))}</a>
First for is taking the distinct values of the tag Type, then for each distinct value of this, the respective values of all the Name tags are derived.
Then using the concat function I have concatenated the Type text with the string generated by string-join, used to add/append the Name and , (comma).
HTH :)

Resources