Exist-DB exclude file from transformation - exist-db

I am currently working on indexing my App.
Upon following a tutorial, I reached a dead end:
err:FORG0001 can not convert '/.../collection.xconf' to xs:integer [at line 65, column 26]
I kind of know where the problem is, but I haven't found a solution for it.
I think that I need to exclude collection.xconf from my function:
declare function app:test($node as node(), $model as map(*)) {
for $doc in collection(concat($config:app-root, "/data/edition"))
let $id := replace(document-uri($doc),".*/([^.]*)\.xml", "$1") cast as xs:integer
order by $id
return
<li class="semanticClassNameFinden" data-target="#carouselIndicators" data-slide-to="{$id - 29}" style="list-style:none;"> Page {$id}v/ {$id+1}r </li>
};
How can I exclude this file from my function?
I thought about adding sth like ?select=*.xml or adding '*.xml' to the "for-line", but doing so only returns in the function not running.
Any other hints?
best wishes,
K

To exclude a file such as collection.xconf from the results returned by the collection() function, you could a predicate to the function to filter out nodes in the undesired namespace. For example, compare the following two queries:
Query 1
xquery version "3.1";
collection("/db/apps/eXide")
This query should return two documents: one with a <package> root element (from expath-pkg.xml) and the other with a <collection> root element (from the collection.xconf file).
Query 2
declare namespace cc="http://exist-db.org/collection-config/1.0";
collection("/db/apps/eXide")[not(cc:collection)]
This query returns only one document: the one with <package> root element (from expath-pkg.xml). It filtered out collection.xconf file.

Related

XQuery/Xpath referring to xml elements with no namespace, in a namespace environment

In Xquery 3.1 (under eXist-DB 4.7) I receive xml data like this, with no namespace:
<edit-request id="TC9999">
<title-collection>foocolltitle</title-collection>
<title-exempla>fooextitle</title-exempla>
<title-short>fooshorttitle</title-short>
</edit-request>
This is assigned to a variable $content and this statement:
let $collid := $content/edit-request/#id
...correctly returns: TC9999
Now, I need to actually transform all the data in $content into a TEI xml document.
I first need to get some info from an existing TEI file, so I assigned another variable:
let $oldcontent := doc(concat($globalvar:URIdata,$collid,"/",$collid,".xml"))
And then I create the new TEI document, referring to both $content and $oldcontent:
let $xml := <listBibl xmlns="http://www.tei-c.org/ns/1.0"
type="collection"
xml:id="{$collid}">
<bibl>
<idno type="old_sql_id">{$oldcontent//tei:idno[#type="old_sql_id"]/text()}</idno>
<title type="collection">{$content//title-exempla/text()}</title>
</bibl>
</listBibl>
The references to the TEI namespace in $oldcontent come through, but to my surprise the references to $content (no namespace) don't show up:
<listBibl xmlns="http://www.tei-c.org/ns/1.0"
type="collection"
xml:id="TC9999">
<bibl>
<idno type="old_sql_id">1</idno>
<title type="collection"/>
</bibl>
</listBibl>
The question is: how do I refer to the non-namespace elements in $content in the context of let $xml=...?
Nb: the Xquery document has a declaration at the top (as it is the principle namespace of virtually all the documents):
declare namespace tei = "http://www.tei-c.org/ns/1.0";
In essence you are asking how to write an XPath expression to select nodes in an empty namespace in a context where the default element namespace is non-empty. One of the most direct solutions is to use the "URI plus local-name syntax" for writing QNames. Here is an example:
xquery version "3.1";
let $x := <x><y>Jbrehr</y></x>
return
<p xmlns="foo">Hey there,
{ $x/Q{}y => string() }!</p>
If instead of $x/Q{}y the example had used the more common form of the path expression, $x/y, its result would have been an empty sequence, since the local name y used to select the <y> element specifies no namespace and thus inherits the foo element namespace from its context. By using the "URI plus local-name syntax", though, we are able to specify the empty namespace we are looking for.
For more information on this, see the XPath 3.1 specification's discussion of expanded QNames: https://www.w3.org/TR/xpath-31/#doc-xpath31-EQName.

Need XPath and XQuery query

I'm working on Xpath/Xquery to return values of multiple child nodes based on a sibling node value in a single query. My XML looks like this
<FilterResults>
<FilterResult>
<ID>535</ID>
<Analysis>
<Name>ZZZZ</Name>
<Identifier>asdfg</Identifier>
<Result>High</Result>
<Score>0</Score>
</Analysis>
<Analysis>
<Name>XXXX</Name>
<Identifier>qwerty</Identifier>
<Result>Medium</Result>
<Score>0</Score>
</Analysis>
</FilterResult>
<FilterResult>
<ID>745</ID>
<Analysis>
<Name>XXXX</Name>
<Identifier>xyz</Identifier>
<Result>Critical</Result>
<Score>0</Score>
</Analysis>
<Analysis>
<Name>YYYY</Name>
<Identifier>qwerty</Identifier>
<Result>Medium</Result>
<Score>0</Score>
</Analysis>
</FilterResult>
</FilterResults>
I need to get values of Score and Identifier based on Name value. I'm currently trying with below query but not working as desired
fn:string-join((
for $Identifier in fn:distinct-values(FilterResults/FilterResult/Analysis[Name="XXXX"])
return fn:string-join((//Identifier,//Score),'-')),',')
The output i'm looking for is this
qwerty-0,xyz-0
Your question suggests some fundamental misunderstandings about XQuery, generally. It's hard to explain everything in a single answer, but 1) that is not how distinct-values works (it returns string values, not nodes), and 2) the double slash selections in your return statement are returning everything because they are not constrained by anything. The XPath you use inside the distinct-values call is very close, however.
Instead of calling distinct-values, you can assign the Analysis results of that XPath to a variable, iterate over them, and generate concatenated strings. Then use string-join to comma separate the full sequence. Note that in the return statement, the variable $a is used to concat only one pair of values at a time.
string-join(
let $analyses := FilterResults/FilterResult/Analysis[Name="XXXX"]
for $a in $analyses
return $a/concat(Identifier, '-', Score),
',')
=> qwerty-0,xyz-0

Xquery - return only distinct attributes from if/then

I've been trying to write a query to get distinct attribute values after using if/then to determine whether I'll use the element in the first place. Here's my example xml and the query i've written so far:
<donors>
<donor donor_id="x21" cn_id="x12">
<homeless>$1201</homeless>
<conservation>$300</conservation>
<cancerResearch>$250</cancerResearch>
</donor>
<donor donor_id="x23" cn_id="x13">
<homeless>$121</homeless>
<conservation>$30</conservation>
<cancerResearch>$50</cancerResearch>
</donor>
<donor donor_id="x24" cn_id="x14">
<homeless>$1201</homeless>
<cancerResearch>$250</cancerResearch>
</donor>
<donor donor_id="x25" cn_id="x12">
<homeless>$1201</homeless>
<conservation>$300</conservation>
<cancerResearch>$250</cancerResearch>
</donor>
</donors>
I want to first get all donors who have a child "conservation". I've done the following for that:
<conservationists>
{
for $x in //donor
return
if(exists($x/conservation))
then <conservationist cn_id="{$x/#cn_id}/>
else ()
}
</conservationists>
I tried wrapping the whole thing in distinct-values but that just gave nothing, and every where else I tried doing something to that effect I just ended up with an end tag.
This is one possible way :
<conservationists>
{
for $x in distinct-values(//donor[conservation]/#cn_id)
return
<conservationist cn_id="{$x}"/>
}
</conservationists>
xpathtester demo
The expression distinct-values(//donor[conservation]/#cn_id) returns distinct values of cn_id attribute from donor elements that have at least one conservation child element.

How to construct an xpath returning all of a set of elements

Considering theses xpath expressions :
//*[#id="searchResults"]/div[1]/div[1]/h2/span
//*[#id="searchResults"]/div[3]/div[1]/h2/span
//*[#id="searchResults"]/div[5]/div[1]/h2/span
For your info the div inside search result's class is article searchResult and the one inside article searchResult is header.
I am not sure how to construct an xpath matching all three of the above elements. Is there a tool or a how to guide for that?
Thanks
Use position function
//*[#id="searchResults"]/div[position()=1 or position()=3 or position()=5]/div[1]/h2/span
If, by 'all', you mean all div in even position index, then you can use mod operator to check :
//*[#id="searchResults"]/div[position() mod 2 = 1]/div[1]/h2/span
but if 'all' literally means all, then you don't need index to return all matched elements :
//*[#id="searchResults"]/div/div[1]/h2/span

Xpath get multiple node-names

i am using xpath to get some node names from a xhtml / xml file.
I currently have this xpath:
/xhtml:html/xhtml:head/xforms:model/xforms:instance/form/*[starts-with(local-name(), 'section')]
That will get the nodes with a name like this:
section-1_s1_partners
section-2-s2_strategy
The result of the above xpath are the matched nodes, but i want to get for each match the full-node-name. When i use the name() function like
name(/xhtml:html/xhtml:head/xforms:model/xforms:instance/form/*[starts-with(local-name(), 'section')])
Then it only returns the first match, and i have no clue how to do it otherwise..
Any great ideas??
Thanks!
(the xhtml/xml: )
<xhtml:html ....>
<xhtml:head>
<xhtml:title>ASD-1</xhtml:title>
<xforms:model id="fr-form-model">
<xforms:instance id="fr-form-instance">
<form>
<section-1_s1_partners>
<control-304/>
<toggleForm>ASD</toggleForm>
<applicationid/>
<section-345>
<s1_kbPaAAr/>
<s1_kbDCCent/>
<s1_kbRAE/>
</section-345>
<section-s1_depDDFentGFress>
<address_search/>
<address_postcode/>
<address_address1/>
<address_address2/>
<address_address3/>
<address_city/>
</section-s1_departmentAddress>
<section-344>
<s1_companyPartner/>
<s1_companyRegistrationNumber/>
<s1_companyType/>
<s1_companySize/>
</section-344>
<section-s1_companyAddress>
<address_search/>
<address_postcode/>
<address_address1/>
<address_address2/>
<address_address3/>
<address_city/>
</section-s1_companyAddress>
<section-324>
<s1_plannedDate/>
<s1_workDescription/>
<s1_publicDescription/>
<s1_numberOfAssociates>1</s1_numberOfAssociates>
<s1_duration/>
<s1b_resubmissionYesNo/>
<s1_GAAGrogramNumber/>
</section-324>
</section-1_s1_partners>
<section-2-s2_strategy>
<control-4/>
<s2_memo_strategic/>
<s2_memo_problems/>
<s2_companyPosition/>
<s2_companyContribution/>
<s2_lackExpertise/>
<s2_essential/>
<s2_companySponsor/>
<s2_seekKnowledge/>
<s2_challenge/>
</section-2-s2_strategy>
The name function need one argument, it cannot take a node list. You have to iterate over the nodelist in the language you are using. For example, in xsh:
for /xhtml:html/xhtml:head/xforms:model/xforms:instance/form/*[starts-with(local-name(), 'section')]
echo name()

Resources