5

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.

callow
  • 517
  • 1
  • 4
  • 15

2 Answers2

5

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.

joemfb
  • 3,056
  • 20
  • 19
4

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')]
wst
  • 11,681
  • 1
  • 24
  • 39