Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Marklogic query based on values of multiple attributes of the same element

Tags:

marklogic

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 searching for the documents where value of id attribute of subject is "001" but role(if it's there) of the same subject element is not "cross".So, In my example the result should contain sample1.xml and not sample2.xml

I thought the following query would do the job:

<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 it does not(returns an empty sequence). Please give me one that does.

like image 294
callow Avatar asked Sep 02 '14 13:09

callow


2 Answers

As @wst said, the cts:not-query matches both documents. cts:* queries match document fragments, not subtrees. You can match the opposite of your conditions, by nesting the cts:element-attribute-value-query constructors inside of a 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 adjust your query requirements so this is sufficient. If not, you can exclude the documents that match this search, using the except operator. 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 could add range indices and use one of the cts:*-values functions to get the unique IDs for documents matching the second cts:search, and then use cts:not-query and cts:*-range-query to exclude the documents from the first cts:search.

like image 129
joemfb Avatar answered Jan 03 '23 15:01

joemfb


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

This may not be sufficient, since it's not an index-only query, but you could supplement the cts:search results 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')]
like image 45
wst Avatar answered Jan 03 '23 15:01

wst