Marklogical query based on the values ​​of several attributes of the same element

I have the following xmls:

sample1.xml <root> <subjectInfo> <subject id="001"/> <subject id="002" role="cross"/> </subjectInfo> </root>

sample2.xml <root> <subjectInfo> <subject id="002"/> <subject id="001" role="cross"/> </subjectInfo> </root>

I am looking for documents in which the value of the subject id attribute is β€œ001”, but the role (if it is there) of the same subject element is not a β€œcross”. So, in my example, the result should contain sample1.xml , not sample2.xml

I thought the following query would complete the task:

 <code> cts:search(/root, cts:near-query(( cts:element-attribute-value-query(xs:QName("subject"),xs:QName("id"),"001"), cts:not-query(cts:element-attribute-value-query(xs:QName("subject"),xs:QName("role"),"cross"))),0) ) </code> 

But this is not so (returns an empty sequence). Please give me the one that does.

+5
source share
2 answers

As pointed out by @wst, cts:not-query matches both documents. cts:* queries correspond to document fragments, not subtrees. You can match the opposite to your conditions by inserting the cts:element-attribute-value-query constructors inside cts:element-query . This will match sample2.xml :

 cts:search(/root, cts:element-query(xs:QName("subject"), cts:and-query(( cts:element-attribute-value-query(xs:QName("subject"),xs:QName("id"),"001"), cts:element-attribute-value-query(xs:QName("subject"),xs:QName("role"),"cross"))))) 

Perhaps you can customize your query requirements to be enough. If not, you can exclude documents matching this search using the except statement. This will match sample1.xml :

 cts:search(/root, cts:element-attribute-value-query(xs:QName("subject"),xs:QName("id"),"001")) except cts:search(/root, cts:element-query(xs:QName("subject"), cts:and-query(( cts:element-attribute-value-query(xs:QName("subject"),xs:QName("id"),"001"), cts:element-attribute-value-query(xs:QName("subject"),xs:QName("role"),"cross"))))) 

If your documents have unique identifiers, you can add range indices and use one of the cts:*-values functions to get unique identifiers for documents matching the second cts:search , and then use cts:not-query and cts:*-range-query to exclude documents from the first cts:search .

+4
source

I think the problem is that cts:not-query matches on both documents and therefore excludes them from the result set.

This may not be enough, since this is not a query only for the index, but you can complement the results of cts:search by filtering out false positives:

 cts:search(/root, cts:element-attribute-value-query(xs:QName("subject"), xs:QName("id"), "001"))[subjectInfo/subject[@id='001' and not(@role='cross')] 
+3
source

Source: https://habr.com/ru/post/1201643/


All Articles