Fix Absolute Path to list with Integer/String key

 - Introduced normalizedXpath to normalize the xpath and cpspath
 - Introduced normalizedAncestorpath to normalize the ancestor path in xpath and cpspath
 - Added new condition in the ANTLR Grammar to capture the invalid path in the xpath
 - Introduced PathParsingException to replace the IllegalStateException

Issue-ID: CPS-961
Change-Id: Ie10f5c6cfc466387e79eec184b933297d1d79587
Signed-off-by: Lathish <lathishbabu.ganesan@est.tech>
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java
index bb3c2d0..847a1d1 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java
@@ -41,6 +41,8 @@
 import lombok.extern.slf4j.Slf4j;
 import org.hibernate.StaleStateException;
 import org.onap.cps.cpspath.parser.CpsPathQuery;
+import org.onap.cps.cpspath.parser.CpsPathUtil;
+import org.onap.cps.cpspath.parser.PathParsingException;
 import org.onap.cps.spi.CpsDataPersistenceService;
 import org.onap.cps.spi.FetchDescendantsOption;
 import org.onap.cps.spi.entities.AnchorEntity;
@@ -174,8 +176,14 @@
         if (isRootXpath(xpath)) {
             return fragmentRepository.findFirstRootByDataspaceAndAnchor(dataspaceEntity, anchorEntity);
         } else {
+            final String normalizedXpath;
+            try {
+                normalizedXpath = CpsPathUtil.getNormalizedXpath(xpath);
+            } catch (final PathParsingException e) {
+                throw new CpsPathException(e.getMessage());
+            }
             return fragmentRepository.getByDataspaceAndAnchorAndXpath(dataspaceEntity, anchorEntity,
-                xpath);
+                    normalizedXpath);
         }
     }
 
@@ -186,8 +194,8 @@
         final AnchorEntity anchorEntity = anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName);
         final CpsPathQuery cpsPathQuery;
         try {
-            cpsPathQuery = CpsPathQuery.createFrom(cpsPath);
-        } catch (final IllegalStateException e) {
+            cpsPathQuery = CpsPathUtil.getCpsPathQuery(cpsPath);
+        } catch (final PathParsingException e) {
             throw new CpsPathException(e.getMessage());
         }
         List<FragmentEntity> fragmentEntities =
@@ -378,12 +386,13 @@
     }
 
     private boolean deleteDataNode(final FragmentEntity parentFragmentEntity, final String targetXpath) {
-        if (parentFragmentEntity.getXpath().equals(targetXpath)) {
+        final String normalizedTargetXpath = CpsPathUtil.getNormalizedXpath(targetXpath);
+        if (parentFragmentEntity.getXpath().equals(normalizedTargetXpath)) {
             fragmentRepository.delete(parentFragmentEntity);
             return true;
         }
         if (parentFragmentEntity.getChildFragments()
-            .removeIf(fragment -> fragment.getXpath().equals(targetXpath))) {
+            .removeIf(fragment -> fragment.getXpath().equals(normalizedTargetXpath))) {
             fragmentRepository.save(parentFragmentEntity);
             return true;
         }
@@ -391,7 +400,8 @@
     }
 
     private boolean deleteAllListElements(final FragmentEntity parentFragmentEntity, final String listXpath) {
-        final String deleteTargetXpathPrefix = listXpath + "[";
+        final String normalizedListXpath = CpsPathUtil.getNormalizedXpath(listXpath);
+        final String deleteTargetXpathPrefix = normalizedListXpath + "[";
         if (parentFragmentEntity.getChildFragments()
             .removeIf(fragment -> fragment.getXpath().startsWith(deleteTargetXpathPrefix))) {
             fragmentRepository.save(parentFragmentEntity);
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceQueryDataNodeSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceQueryDataNodeSpec.groovy
index ae88d30..36b378a 100644
--- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceQueryDataNodeSpec.groovy
+++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceQueryDataNodeSpec.groovy
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2021 Nordix Foundation
+ *  Copyright (C) 2021-2022 Nordix Foundation
  *  Modifications Copyright (C) 2021 Pantheon.tech
  *  Modifications Copyright (C) 2021 Bell Canada.
  *  ================================================================================
@@ -92,15 +92,15 @@
             }
         where: 'the following data is used'
             scenario                                                 | cpsPath                                 || expectedXPaths
-            'fully unique descendant name'                           | '//categories[@code=2]'                 || ['/shops/shop[@id=1]/categories[@code=2]', '/shops/shop[@id=2]/categories[@code=1]', '/shops/shop[@id=2]/categories[@code=2]']
-            'descendant name match end of other node'                | '//book'                                || ['/shops/shop[@id=1]/categories[@code=1]/book', '/shops/shop[@id=1]/categories[@code=2]/book']
-            'descendant with text condition on leaf'                 | '//book/title[text()="Chapters"]'       || ['/shops/shop[@id=1]/categories[@code=2]/book']
+            'fully unique descendant name'                           | '//categories[@code=2]'                 || ["/shops/shop[@id='1']/categories[@code='2']", "/shops/shop[@id='2']/categories[@code='1']", "/shops/shop[@id='2']/categories[@code='2']"]
+            'descendant name match end of other node'                | '//book'                                || ["/shops/shop[@id='1']/categories[@code='1']/book", "/shops/shop[@id='1']/categories[@code='2']/book"]
+            'descendant with text condition on leaf'                 | '//book/title[text()="Chapters"]'       || ["/shops/shop[@id='1']/categories[@code='2']/book"]
             'descendant with text condition case mismatch'           | '//book/title[text()="chapters"]'       || []
-            'descendant with text condition on int leaf'             | '//book/price[text()="5"]'              || ['/shops/shop[@id=1]/categories[@code=1]/book']
-            'descendant with text condition on leaf-list'            | '//book/labels[text()="special offer"]' || ['/shops/shop[@id=1]/categories[@code=1]/book']
+            'descendant with text condition on int leaf'             | '//book/price[text()="5"]'              || ["/shops/shop[@id='1']/categories[@code='1']/book"]
+            'descendant with text condition on leaf-list'            | '//book/labels[text()="special offer"]' || ["/shops/shop[@id='1']/categories[@code='1']/book"]
             'descendant with text condition partial match'           | '//book/labels[text()="special"]'       || []
-            'descendant with text condition (existing) empty string' | '//book/labels[text()=""]'              || ['/shops/shop[@id=1]/categories[@code=1]/book']
-            'descendant with text condition on int leaf-list'        | '//book/editions[text()="2000"]'        || ['/shops/shop[@id=1]/categories[@code=2]/book']
+            'descendant with text condition (existing) empty string' | '//book/labels[text()=""]'              || ["/shops/shop[@id='1']/categories[@code='1']/book"]
+            'descendant with text condition on int leaf-list'        | '//book/editions[text()="2000"]'        || ["/shops/shop[@id='1']/categories[@code='2']/book"]
     }
 
     @Sql([CLEAR_DATA, SET_DATA])
@@ -115,10 +115,10 @@
             }
         where: 'the following data is used'
             scenario                   | cpsPath                                               || expectedXPaths
-            'one leaf'                 | '//author[@FirstName="Joe"]'                          || ['/shops/shop[@id=1]/categories[@code=1]/book/author[@FirstName="Joe" and @Surname="Bloggs"]', '/shops/shop[@id=1]/categories[@code=2]/book/author[@FirstName="Joe" and @Surname="Smith"]']
-            'more than one leaf'       | '//author[@FirstName="Joe" and @Surname="Bloggs"]'    || ['/shops/shop[@id=1]/categories[@code=1]/book/author[@FirstName="Joe" and @Surname="Bloggs"]']
-            'leaves reversed in order' | '//author[@Surname="Bloggs" and @FirstName="Joe"]'    || ['/shops/shop[@id=1]/categories[@code=1]/book/author[@FirstName="Joe" and @Surname="Bloggs"]']
-            'leaf and text condition'  | '//author[@FirstName="Joe"]/Surname[text()="Bloggs"]' || ['/shops/shop[@id=1]/categories[@code=1]/book/author[@FirstName="Joe" and @Surname="Bloggs"]']
+            'one leaf'                 | '//author[@FirstName="Joe"]'                          || ["/shops/shop[@id='1']/categories[@code='1']/book/author[@FirstName='Joe' and @Surname='Bloggs']", "/shops/shop[@id='1']/categories[@code='2']/book/author[@FirstName='Joe' and @Surname='Smith']"]
+            'more than one leaf'       | '//author[@FirstName="Joe" and @Surname="Bloggs"]'    || ["/shops/shop[@id='1']/categories[@code='1']/book/author[@FirstName='Joe' and @Surname='Bloggs']"]
+            'leaves reversed in order' | '//author[@Surname="Bloggs" and @FirstName="Joe"]'    || ["/shops/shop[@id='1']/categories[@code='1']/book/author[@FirstName='Joe' and @Surname='Bloggs']"]
+            'leaf and text condition'  | '//author[@FirstName="Joe"]/Surname[text()="Bloggs"]' || ["/shops/shop[@id='1']/categories[@code='1']/book/author[@FirstName='Joe' and @Surname='Bloggs']"]
     }
 
     @Sql([CLEAR_DATA, SET_DATA])
@@ -133,9 +133,9 @@
             }
         where: 'the following data is used'
             scenario                              | cpsPath                                        || expectedXPaths
-            'one partial key leaf'                | '//author[@FirstName="Joe"]'                   || ['/shops/shop[@id=1]/categories[@code=1]/book/author[@FirstName="Joe" and @Surname="Bloggs"]', '/shops/shop[@id=1]/categories[@code=2]/book/author[@FirstName="Joe" and @Surname="Smith"]']
-            'one non key leaf'                    | '//author[@title="Dune"]'                      || ['/shops/shop[@id=1]/categories[@code=1]/book/author[@FirstName="Joe" and @Surname="Bloggs"]']
-            'mix of partial key and non key leaf' | '//author[@FirstName="Joe" and @title="Dune"]' || ['/shops/shop[@id=1]/categories[@code=1]/book/author[@FirstName="Joe" and @Surname="Bloggs"]']
+            'one partial key leaf'                | '//author[@FirstName="Joe"]'                   || ["/shops/shop[@id='1']/categories[@code='1']/book/author[@FirstName='Joe' and @Surname='Bloggs']", "/shops/shop[@id='1']/categories[@code='2']/book/author[@FirstName='Joe' and @Surname='Smith']"]
+            'one non key leaf'                    | '//author[@title="Dune"]'                      || ["/shops/shop[@id='1']/categories[@code='1']/book/author[@FirstName='Joe' and @Surname='Bloggs']"]
+            'mix of partial key and non key leaf' | '//author[@FirstName="Joe" and @title="Dune"]' || ["/shops/shop[@id='1']/categories[@code='1']/book/author[@FirstName='Joe' and @Surname='Bloggs']"]
     }
 
     @Sql([CLEAR_DATA, SET_DATA])
@@ -149,13 +149,13 @@
             }
         where: 'the following data is used'
             scenario                                    | cpsPath                                              || expectedXPaths
-            'multiple list-ancestors'                   | '//book/ancestor::categories'                        || ['/shops/shop[@id=1]/categories[@code=1]', '/shops/shop[@id=1]/categories[@code=2]']
-            'one ancestor with list value'              | '//book/ancestor::categories[@code=1]'               || ['/shops/shop[@id=1]/categories[@code=1]']
+            'multiple list-ancestors'                   | '//book/ancestor::categories'                        || ["/shops/shop[@id='1']/categories[@code='1']", "/shops/shop[@id='1']/categories[@code='2']"]
+            'one ancestor with list value'              | '//book/ancestor::categories[@code=1]'               || ["/shops/shop[@id='1']/categories[@code='1']"]
             'top ancestor'                              | '//shop[@id=1]/ancestor::shops'                      || ['/shops']
-            'list with index value in the xpath prefix' | '//categories[@code=1]/book/ancestor::shop[@id=1]'   || ['/shops/shop[@id=1]']
-            'ancestor with parent list'                 | '//book/ancestor::shop[@id=1]/categories[@code=2]'   || ['/shops/shop[@id=1]/categories[@code=2]']
-            'ancestor with parent'                      | '//phonenumbers[@type="mob"]/ancestor::info/contact' || ['/shops/shop[@id=3]/info/contact']
-            'ancestor combined with text condition'     | '//book/title[text()="Dune"]/ancestor::shop'         || ['/shops/shop[@id=1]']
+            'list with index value in the xpath prefix' | '//categories[@code=1]/book/ancestor::shop[@id=1]'   || ["/shops/shop[@id='1']"]
+            'ancestor with parent list'                 | '//book/ancestor::shop[@id=1]/categories[@code=2]'   || ["/shops/shop[@id='1']/categories[@code='2']"]
+            'ancestor with parent'                      | '//phonenumbers[@type="mob"]/ancestor::info/contact' || ["/shops/shop[@id='3']/info/contact"]
+            'ancestor combined with text condition'     | '//book/title[text()="Dune"]/ancestor::shop'         || ["/shops/shop[@id='1']"]
             'ancestor with parent that does not exist'  | '//book/ancestor::parentDoesNoExist/categories'      || []
             'ancestor does not exist'                   | '//book/ancestor::ancestorDoesNotExist'              || []
     }
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy
index ab29005..6f780fc 100755
--- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy
+++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy
@@ -23,11 +23,13 @@
 
 import com.fasterxml.jackson.databind.ObjectMapper
 import com.google.common.collect.ImmutableSet
+import org.onap.cps.cpspath.parser.PathParsingException
 import org.onap.cps.spi.CpsDataPersistenceService
 import org.onap.cps.spi.entities.FragmentEntity
 import org.onap.cps.spi.exceptions.AlreadyDefinedException
 import org.onap.cps.spi.exceptions.AnchorNotFoundException
 import org.onap.cps.spi.exceptions.CpsAdminException
+import org.onap.cps.spi.exceptions.CpsPathException
 import org.onap.cps.spi.exceptions.DataNodeNotFoundException
 import org.onap.cps.spi.exceptions.DataspaceNotFoundException
 import org.onap.cps.spi.model.DataNode
@@ -150,7 +152,7 @@
             thrown(expectedException)
         where: 'the following data is used'
             scenario                 | parentXpath                      | dataNode              || expectedException
-            'parent does not exist'  | 'unknown'                        | newDataNode           || DataNodeNotFoundException
+            'parent does not exist'  | '/unknown'                       | newDataNode           || DataNodeNotFoundException
             'already existing child' | XPATH_DATA_NODE_WITH_DESCENDANTS | existingChildDataNode || AlreadyDefinedException
     }
 
@@ -185,9 +187,9 @@
         then: 'a #expectedException is thrown'
             thrown(expectedException)
         where: 'following parameters were used'
-            scenario                     | parentNodeXpath | listElementXpaths                   || expectedException
-            'parent node does not exist' | '/unknown'      | ['irrelevant']                      || DataNodeNotFoundException
-            'already existing fragment'  | '/parent-201'   | ['/parent-201/child-204[@key="A"]'] || AlreadyDefinedException
+            scenario                        | parentNodeXpath | listElementXpaths                   || expectedException
+            'parent node does not exist'    | '/unknown'      | ['irrelevant']                      || DataNodeNotFoundException
+            'data fragment already exists'  | '/parent-201'   | ["/parent-201/child-204[@key='A']"] || AlreadyDefinedException
     }
 
     @Sql([CLEAR_DATA, SET_DATA])
@@ -208,6 +210,15 @@
     }
 
     @Sql([CLEAR_DATA, SET_DATA])
+    def 'Cps Path query with syntax error throws a CPS Path Exception.'() {
+        when: 'trying to execute a query with a syntax (parsing) error'
+            objectUnderTest.getDataNode(DATASPACE_NAME, ANCHOR_FOR_DATA_NODES_WITH_LEAVES, 'invalid-cps-path/child' , OMIT_DESCENDANTS)
+        then: 'exception is thrown'
+            def exceptionThrown = thrown(CpsPathException)
+            assert exceptionThrown.getDetails().contains('failed to parse at line 1 due to extraneous input \'invalid-cps-path\' expecting \'/\'')
+    }
+
+    @Sql([CLEAR_DATA, SET_DATA])
     def 'Get data node by xpath with all descendants.'() {
         when: 'data node is requested with all descendants'
             def result = objectUnderTest.getDataNode(DATASPACE_NAME, ANCHOR_FOR_DATA_NODES_WITH_LEAVES,
@@ -235,10 +246,10 @@
         then: 'a #expectedException is thrown'
             thrown(expectedException)
         where: 'the following data is used'
-            scenario                 | dataspaceName  | anchorName                        | xpath          || expectedException
-            'non-existing dataspace' | 'NO DATASPACE' | 'not relevant'                    | 'not relevant' || DataspaceNotFoundException
-            'non-existing anchor'    | DATASPACE_NAME | 'NO ANCHOR'                       | 'not relevant' || AnchorNotFoundException
-            'non-existing xpath'     | DATASPACE_NAME | ANCHOR_FOR_DATA_NODES_WITH_LEAVES | 'NO XPATH'     || DataNodeNotFoundException
+            scenario                 | dataspaceName  | anchorName                        | xpath           || expectedException
+            'non-existing dataspace' | 'NO DATASPACE' | 'not relevant'                    | '/not relevant' || DataspaceNotFoundException
+            'non-existing anchor'    | DATASPACE_NAME | 'NO ANCHOR'                       | '/not relevant' || AnchorNotFoundException
+            'non-existing xpath'     | DATASPACE_NAME | ANCHOR_FOR_DATA_NODES_WITH_LEAVES | '/NO XPATH'     || DataNodeNotFoundException
     }
 
     @Sql([CLEAR_DATA, SET_DATA])
@@ -265,10 +276,10 @@
         then: 'a #expectedException is thrown'
             thrown(expectedException)
         where: 'the following data is used'
-            scenario                 | dataspaceName  | anchorName                        | xpath                || expectedException
-            'non-existing dataspace' | 'NO DATASPACE' | 'not relevant'                    | 'not relevant'       || DataspaceNotFoundException
-            'non-existing anchor'    | DATASPACE_NAME | 'NO ANCHOR'                       | 'not relevant'       || AnchorNotFoundException
-            'non-existing xpath'     | DATASPACE_NAME | ANCHOR_FOR_DATA_NODES_WITH_LEAVES | 'NON-EXISTING XPATH' || DataNodeNotFoundException
+            scenario                 | dataspaceName  | anchorName                        | xpath                 || expectedException
+            'non-existing dataspace' | 'NO DATASPACE' | 'not relevant'                    | '/not relevant'       || DataspaceNotFoundException
+            'non-existing anchor'    | DATASPACE_NAME | 'NO ANCHOR'                       | '/not relevant'       || AnchorNotFoundException
+            'non-existing xpath'     | DATASPACE_NAME | ANCHOR_FOR_DATA_NODES_WITH_LEAVES | '/NON-EXISTING XPATH' || DataNodeNotFoundException
     }
 
     @Sql([CLEAR_DATA, SET_DATA])
@@ -359,10 +370,10 @@
         then: 'a #expectedException is thrown'
             thrown(expectedException)
         where: 'the following data is used'
-            scenario                 | dataspaceName  | anchorName                        | xpath                || expectedException
-            'non-existing dataspace' | 'NO DATASPACE' | 'not relevant'                    | 'not relevant'       || DataspaceNotFoundException
-            'non-existing anchor'    | DATASPACE_NAME | 'NO ANCHOR'                       | 'not relevant'       || AnchorNotFoundException
-            'non-existing xpath'     | DATASPACE_NAME | ANCHOR_FOR_DATA_NODES_WITH_LEAVES | 'NON-EXISTING XPATH' || DataNodeNotFoundException
+            scenario                 | dataspaceName  | anchorName                        | xpath                 || expectedException
+            'non-existing dataspace' | 'NO DATASPACE' | 'not relevant'                    | '/not relevant'       || DataspaceNotFoundException
+            'non-existing anchor'    | DATASPACE_NAME | 'NO ANCHOR'                       | '/not relevant'       || AnchorNotFoundException
+            'non-existing xpath'     | DATASPACE_NAME | ANCHOR_FOR_DATA_NODES_WITH_LEAVES | '/NON-EXISTING XPATH' || DataNodeNotFoundException
     }
 
     @Sql([CLEAR_DATA, SET_DATA])
@@ -468,10 +479,10 @@
             assert remainingChildXpaths.containsAll(expectedRemainingChildXpaths)
         where: 'following parameters were used'
             scenario                          | targetXpaths                                                 | parentFragmentId                     || expectedRemainingChildXpaths
-            'list element with key'           | '/parent-203/child-204[@key="A"]'                            | LIST_DATA_NODE_PARENT203_FRAGMENT_ID || ['/parent-203/child-203', '/parent-203/child-204[@key="B"]']
-            'list element with combined keys' | '/parent-202/child-205[@key="A" and @key2="B"]'              | LIST_DATA_NODE_PARENT202_FRAGMENT_ID || ['/parent-202/child-206[@key="A"]']
+            'list element with key'           | '/parent-203/child-204[@key="A"]'                            | LIST_DATA_NODE_PARENT203_FRAGMENT_ID || ["/parent-203/child-203", "/parent-203/child-204[@key='B']"]
+            'list element with combined keys' | '/parent-202/child-205[@key="A" and @key2="B"]'              | LIST_DATA_NODE_PARENT202_FRAGMENT_ID || ["/parent-202/child-206[@key='A']"]
             'whole list'                      | '/parent-203/child-204'                                      | LIST_DATA_NODE_PARENT203_FRAGMENT_ID || ['/parent-203/child-203']
-            'list element under list element' | '/parent-203/child-204[@key="B"]/grand-child-204[@key2="Y"]' | LIST_DATA_NODE_PARENT203_FRAGMENT_ID || ['/parent-203/child-203', '/parent-203/child-204[@key="A"]', '/parent-203/child-204[@key="B"]']
+            'list element under list element' | '/parent-203/child-204[@key="B"]/grand-child-204[@key2="Y"]' | LIST_DATA_NODE_PARENT203_FRAGMENT_ID || ["/parent-203/child-203", "/parent-203/child-204[@key='A']", "/parent-203/child-204[@key='B']"]
     }
 
     @Sql([CLEAR_DATA, SET_DATA])
@@ -510,9 +521,9 @@
             'child of target'                       | '/parent-206/child-206'                            | '/parent-206/child-206'                           || null
             'child data node, parent still exists'  | '/parent-206/child-206'                            | '/parent-206'                                     || '/parent-206'
             'list element'                          | '/parent-206/child-206/grand-child-206[@key="A"]'  | '/parent-206/child-206/grand-child-206[@key="A"]' || null
-            'list element, sibling still exists'    | '/parent-206/child-206/grand-child-206[@key="A"]'  | '/parent-206/child-206/grand-child-206[@key="X"]' || '/parent-206/child-206/grand-child-206[@key="X"]'
+            'list element, sibling still exists'    | '/parent-206/child-206/grand-child-206[@key="A"]'  | '/parent-206/child-206/grand-child-206[@key="X"]' || "/parent-206/child-206/grand-child-206[@key='X']"
             'container node'                        | '/parent-206'                                      | '/parent-206'                                     || null
-            'container list node'                   | '/parent-206[@key="A"]'                            | '/parent-206[@key="B"]'                           || '/parent-206[@key="B"]'
+            'container list node'                   | '/parent-206[@key="A"]'                            | '/parent-206[@key="B"]'                           || "/parent-206[@key='B']"
             'root node with xpath /'                | '/'                                                | '/'                                               || null
             'root node with xpath passed as blank'  | ''                                                 | ''                                                || null
 
@@ -523,11 +534,11 @@
         when: 'data node is deleted'
             objectUnderTest.deleteDataNode(DATASPACE_NAME, ANCHOR_NAME3, datanodeXpath)
         then: 'a #expectedException is thrown'
-            thrown(DataNodeNotFoundException)
+            thrown(expectedException)
         where: 'the following parameters were used'
-            scenario                                        | datanodeXpath
-            'valid data node, non existent child node'      | '/parent-203/child-non-existent'
-            'invalid list element'                          | '/parent-206/child-206/grand-child-206@key="A"]'
+            scenario                                        | datanodeXpath                                    | expectedException
+            'valid data node, non existent child node'      | '/parent-203/child-non-existent'                 | DataNodeNotFoundException
+            'invalid list element'                          | '/parent-206/child-206/grand-child-206@key="A"]' | PathParsingException
     }
 
     @Sql([CLEAR_DATA, SET_DATA])
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy
index c508762..52f2309 100644
--- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy
+++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy
@@ -1,6 +1,7 @@
 /*
  * ============LICENSE_START=======================================================
  * Copyright (c) 2021 Bell Canada.
+ * Modifications Copyright (C) 2021-2022 Nordix Foundation
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -45,7 +46,7 @@
 
     def 'Handling of StaleStateException (caused by concurrent updates) during data node tree update.'() {
 
-        def parentXpath = 'parent-01'
+        def parentXpath = '/parent-01'
         def myDataspaceName = 'my-dataspace'
         def myAnchorName = 'my-anchor'
 
@@ -82,7 +83,7 @@
         }
         when: 'getting the data node represented by this fragment'
         def dataNode = objectUnderTest.getDataNode('my-dataspace', 'my-anchor',
-                'parent-01', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS)
+                '/parent-01', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS)
         then: 'the leaf is of the correct value and data type'
         def attributeValue = dataNode.leaves.get('some attribute')
         assert attributeValue == expectedValue
@@ -108,7 +109,7 @@
         }
         when: 'getting the data node represented by this fragment'
         def dataNode = objectUnderTest.getDataNode('my-dataspace', 'my-anchor',
-                'parent-01', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS)
+                '/parent-01', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS)
         then: 'a data validation exception is thrown'
         thrown(DataValidationException)
     }
diff --git a/cps-ri/src/test/resources/data/cps-path-query.sql b/cps-ri/src/test/resources/data/cps-path-query.sql
index 8f525df..d1a6220 100644
--- a/cps-ri/src/test/resources/data/cps-path-query.sql
+++ b/cps-ri/src/test/resources/data/cps-path-query.sql
@@ -1,6 +1,6 @@
 /*
    ============LICENSE_START=======================================================
-    Copyright (C) 2021 Nordix Foundation.
+    Copyright (C) 2021-2022 Nordix Foundation.
     Modifications Copyright (C) 2021 Bell Canada.
    ================================================================================
    Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,25 +30,25 @@
 
 INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH, ATTRIBUTES) VALUES
     (1, 1001, 1003, null, '/shops', null),
-    (2, 1001, 1003, 1, '/shops/shop[@id=1]', '{"id" : 1, "type" : "bookstore"}'),
-    (3, 1001, 1003, 2, '/shops/shop[@id=1]/categories[@code=1]', '{"code" : 1, "type" : "bookstore", "name": "SciFi"}'),
-    (4, 1001, 1003, 2, '/shops/shop[@id=1]/categories[@code=2]', '{"code" : 2, "type" : "bookstore", "name": "Fiction"}'),
-    (5, 1001, 1003, 3, '/shops/shop[@id=1]/categories[@code=1]/book', '{"price" :  5, "title" : "Dune", "labels" : ["special offer","classics",""]}'),
-    (6, 1001, 1003, 4, '/shops/shop[@id=1]/categories[@code=2]/book', '{"price" : 15, "title" : "Chapters", "editions" : [2000,2010,2020]}'),
-    (7, 1001, 1003, 5, '/shops/shop[@id=1]/categories[@code=1]/book/author[@FirstName="Joe" and @Surname="Bloggs"]', '{"FirstName" : "Joe", "Surname": "Bloggs","title": "Dune"}'),
-    (8, 1001, 1003, 6, '/shops/shop[@id=1]/categories[@code=2]/book/author[@FirstName="Joe" and @Surname="Smith"]', '{"FirstName" : "Joe", "Surname": "Smith","title": "Chapters"}');
+    (2, 1001, 1003, 1, '/shops/shop[@id=''1'']', '{"id" : 1, "type" : "bookstore"}'),
+    (3, 1001, 1003, 2, '/shops/shop[@id=''1'']/categories[@code=''1'']', '{"code" : 1, "type" : "bookstore", "name": "SciFi"}'),
+    (4, 1001, 1003, 2, '/shops/shop[@id=''1'']/categories[@code=''2'']', '{"code" : 2, "type" : "bookstore", "name": "Fiction"}'),
+    (5, 1001, 1003, 3, '/shops/shop[@id=''1'']/categories[@code=''1'']/book', '{"price" :  5, "title" : "Dune", "labels" : ["special offer","classics",""]}'),
+    (6, 1001, 1003, 4, '/shops/shop[@id=''1'']/categories[@code=''2'']/book', '{"price" : 15, "title" : "Chapters", "editions" : [2000,2010,2020]}'),
+    (7, 1001, 1003, 5, '/shops/shop[@id=''1'']/categories[@code=''1'']/book/author[@FirstName=''Joe'' and @Surname=''Bloggs'']', '{"FirstName" : "Joe", "Surname": "Bloggs","title": "Dune"}'),
+    (8, 1001, 1003, 6, '/shops/shop[@id=''1'']/categories[@code=''2'']/book/author[@FirstName=''Joe'' and @Surname=''Smith'']', '{"FirstName" : "Joe", "Surname": "Smith","title": "Chapters"}');
 
     INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH, ATTRIBUTES) VALUES
-    (9, 1001, 1003, 1, '/shops/shop[@id=2]', '{"type" : "bookstore"}'),
-    (10, 1001, 1003, 9, '/shops/shop[@id=2]/categories[@code=1]', '{"code" : 2, "type" : "bookstore", "name": "Kids"}'),
-    (11, 1001, 1003, 10, '/shops/shop[@id=2]/categories[@code=2]', '{"code" : 2, "type" : "bookstore", "name": "Fiction"}');
+    (9, 1001, 1003, 1, '/shops/shop[@id=''2'']', '{"type" : "bookstore"}'),
+    (10, 1001, 1003, 9, '/shops/shop[@id=''2'']/categories[@code=''1'']', '{"code" : 2, "type" : "bookstore", "name": "Kids"}'),
+    (11, 1001, 1003, 10, '/shops/shop[@id=''2'']/categories[@code=''2'']', '{"code" : 2, "type" : "bookstore", "name": "Fiction"}');
 
     INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH, ATTRIBUTES) VALUES
-    (12, 1001, 1003, 1, '/shops/shop[@id=3]', '{"type" : "garden centre"}'),
-    (13, 1001, 1003, 12, '/shops/shop[@id=3]/categories[@code=1]', '{"id" : 1, "type" : "garden centre", "name": "indoor plants"}'),
-    (14, 1001, 1003, 12, '/shops/shop[@id=3]/categories[@code=2]', '{"id" : 2, "type" : "garden centre", "name": "outdoor plants"}'),
-    (16, 1001, 1003, 1, '/shops/shop[@id=3]/info', null),
-    (17, 1001, 1003, 1, '/shops/shop[@id=3]/info/contact', null),
-    (18, 1001, 1003, 1, '/shops/shop[@id=3]/info/contact/website', '{"address" : "myshop.ie"}'),
-    (19, 1001, 1003, 12, '/shops/shop[@id=3]/info/contact/phonenumbers[@type="mob"]', '{"type" : "mob", "number" : "123123456"}'),
-    (20, 1001, 1003, 12, '/shops/shop[@id=3]/info/contact/phonenumbers[@type="landline"]', '{"type" : "landline", "number" : "012123456"}');
+    (12, 1001, 1003, 1, '/shops/shop[@id=''3'']', '{"type" : "garden centre"}'),
+    (13, 1001, 1003, 12, '/shops/shop[@id=''3'']/categories[@code=''1'']', '{"id" : 1, "type" : "garden centre", "name": "indoor plants"}'),
+    (14, 1001, 1003, 12, '/shops/shop[@id=''3'']/categories[@code=''2'']', '{"id" : 2, "type" : "garden centre", "name": "outdoor plants"}'),
+    (16, 1001, 1003, 1, '/shops/shop[@id=''3'']/info', null),
+    (17, 1001, 1003, 1, '/shops/shop[@id=''3'']/info/contact', null),
+    (18, 1001, 1003, 1, '/shops/shop[@id=''3'']/info/contact/website', '{"address" : "myshop.ie"}'),
+    (19, 1001, 1003, 12, '/shops/shop[@id=''3'']/info/contact/phonenumbers[@type=''mob'']', '{"type" : "mob", "number" : "123123456"}'),
+    (20, 1001, 1003, 12, '/shops/shop[@id=''3'']/info/contact/phonenumbers[@type=''landline'']', '{"type" : "landline", "number" : "012123456"}');
diff --git a/cps-ri/src/test/resources/data/fragment.sql b/cps-ri/src/test/resources/data/fragment.sql
index fb4a5f7..4106541 100755
--- a/cps-ri/src/test/resources/data/fragment.sql
+++ b/cps-ri/src/test/resources/data/fragment.sql
@@ -52,32 +52,32 @@
     (4203, 1001, 3003, 4202, '/parent-200/child-201/grand-child', '{"leaf-value": "original"}'),
     (4206, 1001, 3003, null, '/parent-201', '{"leaf-value": "original"}'),
     (4207, 1001, 3003, 4206, '/parent-201/child-203', '{}'),
-    (4208, 1001, 3003, 4206, '/parent-201/child-204[@key="A"]', '{"key": "A"}'),
-    (4209, 1001, 3003, 4206, '/parent-201/child-204[@key="B"]', '{"key": "B"}'),
+    (4208, 1001, 3003, 4206, '/parent-201/child-204[@key=''A'']', '{"key": "A"}'),
+    (4209, 1001, 3003, 4206, '/parent-201/child-204[@key=''B'']', '{"key": "B"}'),
     (4211, 1001, 3003, null, '/parent-202', '{"leaf-value": "original"}'),
-    (4212, 1001, 3003, 4211, '/parent-202/child-205[@key="A" and @key2="B"]', '{"key": "A", "key2": "B"}'),
-    (4213, 1001, 3003, 4211, '/parent-202/child-206[@key="A"]', '{"key": "A"}'),
+    (4212, 1001, 3003, 4211, '/parent-202/child-205[@key=''A'' and @key2=''B'']', '{"key": "A", "key2": "B"}'),
+    (4213, 1001, 3003, 4211, '/parent-202/child-206[@key=''A'']', '{"key": "A"}'),
     (4214, 1001, 3003, null, '/parent-203', '{"leaf-value": "original"}'),
     (4215, 1001, 3003, 4214, '/parent-203/child-203', '{}'),
-    (4216, 1001, 3003, 4214, '/parent-203/child-204[@key="A"]', '{"key": "A"}'),
-    (4217, 1001, 3003, 4214, '/parent-203/child-204[@key="B"]', '{"key": "B"}'),
-    (4218, 1001, 3003, 4217, '/parent-203/child-204[@key="B"]/grand-child-204[@key2="Y"]', '{"key": "B", "key2": "Y"}'),
+    (4216, 1001, 3003, 4214, '/parent-203/child-204[@key=''A'']', '{"key": "A"}'),
+    (4217, 1001, 3003, 4214, '/parent-203/child-204[@key=''B'']', '{"key": "B"}'),
+    (4218, 1001, 3003, 4217, '/parent-203/child-204[@key=''B'']/grand-child-204[@key2=''Y'']', '{"key": "B", "key2": "Y"}'),
     (4226, 1001, 3003, null, '/parent-206', '{"leaf-value": "original"}'),
     (4227, 1001, 3003, 4226, '/parent-206/child-206', '{}'),
     (4228, 1001, 3003, 4227, '/parent-206/child-206/grand-child-206', '{}'),
-    (4229, 1001, 3003, 4227, '/parent-206/child-206/grand-child-206[@key="A"]', '{"key": "A"}'),
-    (4230, 1001, 3003, 4227, '/parent-206/child-206/grand-child-206[@key="X"]', '{"key": "X"}'),
-    (4231, 1001, 3003, null, '/parent-206[@key="A"]', '{"key": "A"}'),
-    (4232, 1001, 3003, 4231, '/parent-206[@key="A"]/child-206', '{}'),
-    (4233, 1001, 3003, null, '/parent-206[@key="B"]', '{"key": "B"}');
+    (4229, 1001, 3003, 4227, '/parent-206/child-206/grand-child-206[@key=''A'']', '{"key": "A"}'),
+    (4230, 1001, 3003, 4227, '/parent-206/child-206/grand-child-206[@key=''X'']', '{"key": "X"}'),
+    (4231, 1001, 3003, null, '/parent-206[@key=''A'']', '{"key": "A"}'),
+    (4232, 1001, 3003, 4231, '/parent-206[@key=''A'']/child-206', '{}'),
+    (4233, 1001, 3003, null, '/parent-206[@key=''B'']', '{"key": "B"}');
 
 INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH, ATTRIBUTES) VALUES
-    (5000, 1002, 3004, null, '/dmi-registry/cm-handles[@id="PNFDemo"]', '{"id": "PNFDemo", "dmi-service-name": "http://172.21.235.14:8783", "dmi-data-service-name": "", "dmi-model-service-name": ""}'),
-    (5001, 1002, 3004, null, '/dmi-registry/cm-handles[@id="PNFDemo2"]', '{"id": "PNFDemo2", "dmi-service-name": "http://172.26.46.68:8783", "dmi-data-service-name": "", "dmi-model-service-name": ""}'),
-    (5002, 1002, 3004, null, '/dmi-registry/cm-handles[@id="PNFDemo3"]', '{"id": "PNFDemo3", "dmi-service-name": "http://172.26.46.68:8783", "dmi-data-service-name": "", "dmi-model-service-name": ""}'),
-    (5003, 1002, 3004, null, '/dmi-registry/cm-handles[@id="PNFDemo4"]', '{"id": "PNFDemo4", "dmi-service-name": "http://172.26.46.68:8783", "dmi-data-service-name": "", "dmi-model-service-name": ""}'),
-    (5004, 1002, 3004, 5000, '/dmi-registry/cm-handles[@id="PNFDemo"]/public-properties[@name="Contact"]', '{"name": "Contact", "value": "newemailforstore@bookstore.com"}'),
-    (5005, 1002, 3004, 5001, '/dmi-registry/cm-handles[@id="PNFDemo2"]/public-properties[@name="Contact"]', '{"name": "Contact", "value": "newemailforstore@bookstore.com"}'),
-    (5006, 1002, 3004, 5002, '/dmi-registry/cm-handles[@id="PNFDemo3"]/public-properties[@name="Contact"]', '{"name": "Contact3", "value": "PNF3@bookstore.com"}'),
-    (5007, 1002, 3004, 5003, '/dmi-registry/cm-handles[@id="PNFDemo4"]/public-properties[@name="Contact"]', '{"name": "Contact", "value": "newemailforstore@bookstore.com"}'),
-    (5008, 1002, 3004, 5004, '/dmi-registry/cm-handles[@id="PNFDemo4"]/public-properties[@name="Contact2"]', '{"name": "Contact2", "value": "newemailforstore2@bookstore.com"}');
\ No newline at end of file
+    (5000, 1002, 3004, null, '/dmi-registry/cm-handles[@id=''PNFDemo'']', '{"id": "PNFDemo", "dmi-service-name": "http://172.21.235.14:8783", "dmi-data-service-name": "", "dmi-model-service-name": ""}'),
+    (5001, 1002, 3004, null, '/dmi-registry/cm-handles[@id=''PNFDemo2'']', '{"id": "PNFDemo2", "dmi-service-name": "http://172.26.46.68:8783", "dmi-data-service-name": "", "dmi-model-service-name": ""}'),
+    (5002, 1002, 3004, null, '/dmi-registry/cm-handles[@id=''PNFDemo3'']', '{"id": "PNFDemo3", "dmi-service-name": "http://172.26.46.68:8783", "dmi-data-service-name": "", "dmi-model-service-name": ""}'),
+    (5003, 1002, 3004, null, '/dmi-registry/cm-handles[@id=''PNFDemo4'']', '{"id": "PNFDemo4", "dmi-service-name": "http://172.26.46.68:8783", "dmi-data-service-name": "", "dmi-model-service-name": ""}'),
+    (5004, 1002, 3004, 5000, '/dmi-registry/cm-handles[@id=''PNFDemo'']/public-properties[@name=''Contact'']', '{"name": "Contact", "value": "newemailforstore@bookstore.com"}'),
+    (5005, 1002, 3004, 5001, '/dmi-registry/cm-handles[@id=''PNFDemo2'']/public-properties[@name=''Contact'']', '{"name": "Contact", "value": "newemailforstore@bookstore.com"}'),
+    (5006, 1002, 3004, 5002, '/dmi-registry/cm-handles[@id=''PNFDemo3'']/public-properties[@name=''Contact'']', '{"name": "Contact3", "value": "PNF3@bookstore.com"}'),
+    (5007, 1002, 3004, 5003, '/dmi-registry/cm-handles[@id=''PNFDemo4'']/public-properties[@name=''Contact'']', '{"name": "Contact", "value": "newemailforstore@bookstore.com"}'),
+    (5008, 1002, 3004, 5004, '/dmi-registry/cm-handles[@id=''PNFDemo4'']/public-properties[@name=''Contact2'']', '{"name": "Contact2", "value": "newemailforstore2@bookstore.com"}');