Search code examples
xpathxquerymarklogic

CTS and xPath both necessary?


I have the following CTS search query:

cts:search(/parent, 
    cts:and-query((
        cts:element-attribute-value-query(xs:QName('parent'), xs:QName('attr'), 'value'),
        cts:element-attribute-value-query(xs:QName('child'), xs:QName('attr-1'), 'value-2'),
        cts:element-attribute-value-query(xs:QName('child'), xs:QName('attr-2'), 'value-3')
    ))
)/child[@attr-1 eq 'value-2' and @attr-2 eq "value-3"]

(: Returns /parent/child elements matching criteria :)

I have some qualifiers on the parent, as well as qualifiers on the children. The end result I want is just the children though. In order to do that, as you can see from above, I have to:

  • Search for documents that match parent criteria + children criteria
  • After getting that document, filter out the children by the same criteria logic as above

This works, but it seems really dumb that I must have the same logic in the cts:query as I do on the xPath for the children. The logic is duplicated unnecessarily.

Is there a way that I can do this all in the cts:query, and not have to have additional xPath expressions, as in the sample above?


This is similar to what I want, but it doesn't work for the problem specified in the comments:

cts:search(/parent/child, 
    cts:and-query((
        cts:element-attribute-value-query(xs:QName('parent'), xs:QName('attr'), 'value'), (: The problem is this line... I can't filter by the parent, as it is above the scope of my first parameter (/parent/rule) :)
        cts:element-attribute-value-query(xs:QName('child'), xs:QName('attr-1'), 'value-2'),
        cts:element-attribute-value-query(xs:QName('child'), xs:QName('attr-2'), 'value-3')
    ))
)

Solution

  • You can still query the parent, even if your search is across the child:

    cts:search(/parent/child, 
        cts:and-query((
            cts:element-attribute-value-query(xs:QName('parent'), xs:QName('attr'), 'value'),
            cts:element-attribute-value-query(xs:QName('child'), xs:QName('attr-1'), 'value-2'),
            cts:element-attribute-value-query(xs:QName('child'), xs:QName('attr-2'), 'value-3')
        ))
    )
    

    This will run as a filtered search, but since you were manually doing the filtering anyway, the performance should be roughly equivalent.

    Update:

    I tested this and the above assertion is wrong. I thought it was right, but evidently cts:search filtering will filter results that don't match on the searchable expression exactly. A parent would be outside of the scope of the searchable expression.

    Ideally, you would break up your documents on the child element, but you can at least remove the overlapping queries and XPath like this:

    cts:search(/parent/child, 
        cts:and-query((
            cts:element-attribute-value-query(xs:QName('child'), xs:QName('attr-1'), 'value-2'),
            cts:element-attribute-value-query(xs:QName('child'), xs:QName('attr-2'), 'value-3')
        ))
    )[parent::parent/@attr = 'value']