'parent & child with more than one attribute has OR operator' | '/parent/child[@key1=1 or @key2="abc"]/child2' || "/parent/child[@key1='1' or @key2='abc']/child2"
'parent & child with multiple AND operators' | '/parent/child[@key1=1 and @key2="abc" and @key="xyz"]/child2' || "/parent/child[@key1='1' and @key2='abc' and @key='xyz']/child2"
'parent & child with multiple OR operators' | '/parent/child[@key1=1 or @key2="abc" or @key="xyz"]/child2' || "/parent/child[@key1='1' or @key2='abc' or @key='xyz']/child2"
+ 'parent & child with multiple AND/OR combination' | '/parent/child[@key1=1 and @key2="abc" or @key="xyz"]/child2' || "/parent/child[@key1='1' and @key2='abc' or @key='xyz']/child2"
+ 'parent & child with multiple OR/AND combination' | '/parent/child[@key1=1 or @key2="abc" and @key="xyz"]/child2' || "/parent/child[@key1='1' or @key2='abc' and @key='xyz']/child2"
}
def 'Parse xpath to form the Normalized xpath containing #scenario.'() {
and: 'the right parameters are set'
result.descendantName == "child"
result.leavesData.size() == expectedNumberOfLeaves
+ and: 'the given operator(s) returns in the correct order'
result.booleanOperatorsType == expectedOperators
where: 'the following data is used'
- scenario | cpsPath || expectedNumberOfLeaves || expectedOperators
- 'one attribute' | '//child[@common-leaf-name-int=5]' || 1 || null
- 'more than one attribute has AND operator' | '//child[@int-leaf=5 and @leaf-name="leaf value"]' || 2 || ['and']
- 'more than one attribute has OR operator' | '//child[@int-leaf=5 or @leaf-name="leaf value"]' || 2 || ['or']
- 'more than one attribute has combinations and/or operator' | '//child[@int-leaf=5 and @leaf-name="leaf value" and @leaf-name="leaf value1" ]' || 2 || ['and', 'and']
- 'more than one attribute has combinations or/and operator' | '//child[@int-leaf=5 or @leaf-name="leaf value" or @leaf-name="leaf value1" ]' || 2 || ['or', 'or']
+ scenario | cpsPath || expectedNumberOfLeaves || expectedOperators
+ 'one attribute' | '//child[@common-leaf-name-int=5]' || 1 || null
+ 'more than one attribute has AND operator' | '//child[@int-leaf=5 and @leaf-name="leaf value"]' || 2 || ['and']
+ 'more than one attribute has OR operator' | '//child[@int-leaf=5 or @leaf-name="leaf value"]' || 2 || ['or']
+ 'more than one attribute has combinations and operators' | '//child[@int-leaf=5 and @leaf-name="leaf value" and @leaf-name="leaf value1" ]' || 2 || ['and', 'and']
+ 'more than one attribute has combinations or operators' | '//child[@int-leaf=5 or @leaf-name="leaf value" or @leaf-name="leaf value1" ]' || 2 || ['or', 'or']
+ 'more than one attribute has combinations and/or combination' | '//child[@int-leaf=5 and @leaf-name="leaf value" or @leaf-name="leaf value1" ]' || 2 || ['and', 'or']
+ 'more than one attribute has combinations or/and combination' | '//child[@int-leaf=5 or @leaf-name="leaf value" and @leaf-name="leaf value1" ]' || 2 || ['or', 'and']
}
def 'Parse #scenario cps path with text function condition'() {
'descendant with leaf value and ancestor' | '//child[@other-leaf=1]/leaf-name[text()="search"]/ancestor::parent' || true | true
}
- def 'Parse #scenario cps path with contains function condition'() {
+ def 'Parse cps path with contains function condition'() {
when: 'the given cps path is parsed'
def result = CpsPathQuery.createFrom('//someContainer[contains(@lang,"en")]')
then: 'the query has the right xpath type'
.. This work is licensed under a Creative Commons Attribution 4.0 International License.
.. http://creativecommons.org/licenses/by/4.0
.. Copyright (C) 2021-2022 Nordix Foundation
+.. Modifications Copyright (C) 2023 TechMahindra Ltd
.. DO NOT CHANGE THIS LABEL FOR RELEASE NOTES - EVEN THOUGH IT GIVES A WARNING
.. _path:
leaf-conditions
---------------
-**Syntax**: ``<xpath> '[' @<leaf-name1> '=' <leaf-value1> ( ' and ' @<leaf-name> '=' <leaf-value> )* ']'``
+**Syntax**: ``<xpath> '[' @<leaf-name1> '=' <leaf-value1> ( ' <and|or> ' @<leaf-name> '=' <leaf-value> )* ']'``
- ``xpath``: Absolute or descendant or xpath to the (list) node which elements will be queried.
- ``leaf-name``: The name of the leaf which value needs to be compared.
- ``leaf-value``: The required value of the leaf.
- ``//categories[@name="Kids"]``
- ``//categories[@name='Kids']``
- ``//categories[@code='1']/books/book[@title='Dune' and @price=5]``
+ - ``//categories[@code='1']/books/book[@title='xyz' or @price=15]``
- ``//categories[@code=1]``
**Limitations**
- Only the last list or container can be queried leaf values. Any ancestor list will have to be referenced by its key name-value pair(s).
- - Multiple attributes can only be combined using ``and``. ``or`` and bracketing is not supported.
+ - When mixing ``and/or`` operators, ``and`` has precedence over ``or`` . So ``and`` operators get evaluated first.
+ - Bracketing is not supported.
+ - Leaf names are not validated so ``or`` operations with invalid leaf names will silently be ignored.
- Only leaves can be used, leaf-list are not supported.
- Only string and integer values are supported, boolean and float values are not supported.
- The key should be supplied with correct data type for it to be queried from DB. In the last example above the attribute code is of type
assert result.leaves.sort() == expectedLeaves.sort()
println(expectedLeaves.toArray())
where: 'the following data is used'
- scenario | cpspath || expectedResultSize | expectedLeaves
- 'the "OR" condition' | '//books[@lang="English" or @price=15]' || 6 | [[lang: "English", price: 15, title: "Annihilation", authors: ["Jeff VanderMeer"], editions: [2014]],
- [lang: "English", price: 15, title: "The Gruffalo", authors: ["Julia Donaldson"], editions: [1999]],
- [lang: "English", price: 14, title: "The Light Fantastic", authors: ["Terry Pratchett"], editions: [1986]],
- [lang: "English", price: 13, title: "Good Omens", authors: ["Terry Pratchett", "Neil Gaiman"], editions: [2006]],
- [lang: "English", price: 12, title: "The Colour of Magic", authors: ["Terry Pratchett"], editions: [1983]],
- [lang: "English", price: 10, title: "Matilda", authors: ["Roald Dahl"], editions: [1988, 2000]]]
- 'the "OR" condition with non-json data' | '//books[@title="xyz" or @price=15]' || 2 | [[lang: "English", price: 15, title: "Annihilation", authors: ["Jeff VanderMeer"], editions: [2014]],
- [lang: "English", price: 15, title: "The Gruffalo", authors: ["Julia Donaldson"], editions: [1999]]]
- 'combination of multiple AND' | '//books[@lang="English" and @price=15 and @edition=1983]' || 0 | []
- 'combination of multiple OR' | '//books[ @title="Matilda" or @price=15 or @edition=1983]' || 3 | [[lang: "English", price: 15, title: "Annihilation", authors: ["Jeff VanderMeer"], editions: [2014]],
- [lang: "English", price: 10, title: "Matilda", authors: ["Roald Dahl"], editions: [1988, 2000]],
- [lang: "English", price: 15, title: "The Gruffalo", authors: ["Julia Donaldson"], editions: [1999]]]
+ scenario | cpspath || expectedResultSize | expectedLeaves
+ 'the "OR" condition' | '//books[@lang="English" or @price=15]' || 6 | [[lang: "English", price: 15, title: "Annihilation", authors: ["Jeff VanderMeer"], editions: [2014]],
+ [lang: "English", price: 15, title: "The Gruffalo", authors: ["Julia Donaldson"], editions: [1999]],
+ [lang: "English", price: 14, title: "The Light Fantastic", authors: ["Terry Pratchett"], editions: [1986]],
+ [lang: "English", price: 13, title: "Good Omens", authors: ["Terry Pratchett", "Neil Gaiman"], editions: [2006]],
+ [lang: "English", price: 12, title: "The Colour of Magic", authors: ["Terry Pratchett"], editions: [1983]],
+ [lang: "English", price: 10, title: "Matilda", authors: ["Roald Dahl"], editions: [1988, 2000]]]
+ 'the "OR" condition with non-json data' | '//books[@title="xyz" or @price=15]' || 2 | [[lang: "English", price: 15, title: "Annihilation", authors: ["Jeff VanderMeer"], editions: [2014]],
+ [lang: "English", price: 15, title: "The Gruffalo", authors: ["Julia Donaldson"], editions: [1999]]]
+ 'combination of multiple AND' | '//books[@lang="English" and @price=15 and @edition=1983]' || 0 | []
+ 'combination of multiple OR' | '//books[ @title="Matilda" or @price=15 or @edition=1983]' || 3 | [[lang: "English", price: 15, title: "Annihilation", authors: ["Jeff VanderMeer"], editions: [2014]],
+ [lang: "English", price: 10, title: "Matilda", authors: ["Roald Dahl"], editions: [1988, 2000]],
+ [lang: "English", price: 15, title: "The Gruffalo", authors: ["Julia Donaldson"], editions: [1999]]]
+ 'combination of AND/OR' | '//books[@edition=1983 and @price=15 or @title="Good Omens"]' || 1 | [[lang: "English", price: 13, title: "Good Omens", authors: ["Terry Pratchett", "Neil Gaiman"], editions: [2006]]]
+ 'combination of OR/AND' | '//books[@title="Annihilation" or @price=39 and @lang="arabic"]' || 1 | [[lang: "English", price: 15, title: "Annihilation", authors: ["Jeff VanderMeer"], editions: [2014]]]
}
def 'Cps Path query for leaf value(s) with #scenario.'() {
def bookTitles = result.collect { it.getLeaves().get('title') }
assert bookTitles.sort() == expectedBookTitles.sort()
where: 'the following data is used'
- scenario | cpsPath || expectedBookTitles
- 'one leaf' | '//books[@price=14]' || ['The Light Fantastic']
- 'one text' | '//books/authors[text()="Terry Pratchett"]' || ['Good Omens', 'The Colour of Magic', 'The Light Fantastic']
- 'more than one leaf' | '//books[@price=12 and @lang="English"]' || ['The Colour of Magic']
- 'more than one leaf has "OR" condition' | '//books[@lang="English" or @price=15]' || ['Annihilation', 'Good Omens', 'Matilda', 'The Colour of Magic', 'The Gruffalo', 'The Light Fantastic']
- 'more than one leaf has "OR" condition with non-json data' | '//books[@title="xyz" or @price=13]' || ['Good Omens']
- 'more than one leaf has multiple AND' | '//books[@lang="English" and @price=13 and @edition=1983]' || []
- 'more than one leaf has multiple OR' | '//books[ @title="Matilda" or @price=15 or @edition=2006]' || ['Annihilation', 'Matilda', 'The Gruffalo']
- 'leaves reversed in order' | '//books[@lang="English" and @price=12]' || ['The Colour of Magic']
- 'leaf and text' | '//books[@price=14]/authors[text()="Terry Pratchett"]' || ['The Light Fantastic']
- 'leaf and contains' | '//books[contains(@price,"13")]' || ['Good Omens']
+ scenario | cpsPath || expectedBookTitles
+ 'one leaf' | '//books[@price=14]' || ['The Light Fantastic']
+ 'one text' | '//books/authors[text()="Terry Pratchett"]' || ['Good Omens', 'The Colour of Magic', 'The Light Fantastic']
+ 'more than one leaf' | '//books[@price=12 and @lang="English"]' || ['The Colour of Magic']
+ 'more than one leaf has "OR" condition' | '//books[@lang="English" or @price=15]' || ['Annihilation', 'Good Omens', 'Matilda', 'The Colour of Magic', 'The Gruffalo', 'The Light Fantastic']
+ 'more than one leaf has "OR" condition with non-json data' | '//books[@title="xyz" or @price=13]' || ['Good Omens']
+ 'more than one leaf has multiple AND' | '//books[@lang="English" and @price=13 and @edition=1983]' || []
+ 'more than one leaf has multiple OR' | '//books[ @title="Matilda" or @price=15 or @edition=2006]' || ['Annihilation', 'Matilda', 'The Gruffalo']
+ 'leaves reversed in order' | '//books[@lang="English" and @price=12]' || ['The Colour of Magic']
+ 'more than one leaf has combination of AND/OR' | '//books[@edition=1983 and @price=13 or @title="Good Omens"]' || ['Good Omens']
+ 'more than one leaf has OR/AND' | '//books[@title="The Light Fantastic" or @price=11 and @edition=1983]' || ['The Light Fantastic']
+ 'leaf and text' | '//books[@price=14]/authors[text()="Terry Pratchett"]' || ['The Light Fantastic']
+ 'leaf and contains' | '//books[contains(@price,"13")]' || ['Good Omens']
}
def 'Cps Path query using descendant anywhere with #scenario condition(s) for a list element.'() {