diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/xml/XmlToXPathsConverter.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/xml/XmlToXPathsConverter.groovy
index 9b6bb1da9e..17d692c09e 100644
--- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/xml/XmlToXPathsConverter.groovy
+++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/xml/XmlToXPathsConverter.groovy
@@ -42,7 +42,7 @@ import org.springframework.cloud.contract.spec.internal.MatchingTypeValue
import org.springframework.cloud.contract.spec.internal.PathBodyMatcher
import static java.util.stream.Collectors.toList
-import static javax.xml.xpath.XPathConstants.NODE
+import static javax.xml.xpath.XPathConstants.NODESET
import static org.apache.commons.lang3.StringUtils.isBlank
import static org.w3c.dom.Node.ATTRIBUTE_NODE
import static org.w3c.dom.Node.CDATA_SECTION_NODE
@@ -52,7 +52,6 @@ import static org.w3c.dom.Node.DOCUMENT_TYPE_NODE
import static org.w3c.dom.Node.NOTATION_NODE
import static org.w3c.dom.Node.PROCESSING_INSTRUCTION_NODE
import static org.w3c.dom.Node.TEXT_NODE
-
/**
* @author Olga Maciaszek-Sharma
* @since 2.1.0
@@ -69,8 +68,8 @@ class XmlToXPathsConverter {
.parse(new InputSource(new StringReader(body as String)))
xPath.setNamespaceContext(new DOMNamespaceContext(parsedXml.documentElement))
bodyMatchers?.matchers()?.each({
- Node node = xPath.evaluate(it.path(), parsedXml.documentElement, NODE) as Node
- removeNode(node)
+ NodeList nodes = xPath.evaluate(it.path(), parsedXml.documentElement, NODESET) as NodeList
+ nodes.each {removeNode(it)}
})
parsedXml.normalizeDocument()
return xmlToString(parsedXml)
diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/xml/XmlToXPathsConverterSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/xml/XmlToXPathsConverterSpec.groovy
index d481e9de65..22ca5ea8e2 100644
--- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/xml/XmlToXPathsConverterSpec.groovy
+++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/xml/XmlToXPathsConverterSpec.groovy
@@ -1,11 +1,13 @@
package org.springframework.cloud.contract.verifier.util.xml
-import org.springframework.cloud.contract.spec.internal.BodyMatchers
+import javax.xml.xpath.XPathExpressionException
+
+import spock.lang.Issue
import spock.lang.Shared
import spock.lang.Specification
import spock.lang.Unroll
-import javax.xml.xpath.XPathExpressionException
+import org.springframework.cloud.contract.spec.internal.BodyMatchers
class XmlToXPathsConverterSpec extends Specification {
@Shared
@@ -28,46 +30,65 @@ class XmlToXPathsConverterSpec extends Specification {
@Unroll
def "should generate [#expectedValue] for xPath [#value]"() {
expect:
- value == expectedValue
+ value == expectedValue
where:
- value || expectedValue
- XmlToXPathsConverter.retrieveValueFromBody("/ns1:customer/email/text()", namedXml) || '''customer@test.com'''
- XmlToXPathsConverter.retrieveValueFromBody("/customer/email/text()", namedXml) || ''''''
- XmlToXPathsConverter.retrieveValueFromBody("/customer/email/text()", unnamedXml) || '''customer@test.com'''
+ value || expectedValue
+ XmlToXPathsConverter.retrieveValueFromBody("/ns1:customer/email/text()", namedXml) || '''customer@test.com'''
+ XmlToXPathsConverter.retrieveValueFromBody("/customer/email/text()", namedXml) || ''''''
+ XmlToXPathsConverter.retrieveValueFromBody("/customer/email/text()", unnamedXml) || '''customer@test.com'''
}
@Unroll
def "should throw exception when searching for in existent name space"() {
when:
- XmlToXPathsConverter.retrieveValueFromBody("/ns1:customer/email/text()", unnamedXml)
+ XmlToXPathsConverter.retrieveValueFromBody("/ns1:customer/email/text()", unnamedXml)
then:
- def e = thrown(XPathExpressionException)
- e.message.contains('Prefix must resolve to a namespace: ns1')
+ def e = thrown(XPathExpressionException)
+ e.message.contains('Prefix must resolve to a namespace: ns1')
}
@Unroll
def "should generate matched path [#expectedValue] for xPath [#value]"() {
expect:
- value == expectedValue
+ value == expectedValue
where:
- value || expectedValue
- XmlToXPathsConverter.mapToMatchers(attributesInChildXml).get(0).path() || '''/customer/email/text()'''
- XmlToXPathsConverter.mapToMatchers(attributesInChildXml).get(1).path() || '''/customer/@first_custom_attribute'''
- XmlToXPathsConverter.mapToMatchers(attributesInChildXml).get(2).path() || '''/customer/email/@second_custom_attribute'''
- XmlToXPathsConverter.mapToMatchers(attributesInChildXml).get(3).path() || '''/customer/address/@third_custom_attribute'''
+ value || expectedValue
+ XmlToXPathsConverter.mapToMatchers(attributesInChildXml).get(0).path() || '''/customer/email/text()'''
+ XmlToXPathsConverter.mapToMatchers(attributesInChildXml).get(1).path() || '''/customer/@first_custom_attribute'''
+ XmlToXPathsConverter.mapToMatchers(attributesInChildXml).get(2).path() || '''/customer/email/@second_custom_attribute'''
+ XmlToXPathsConverter.mapToMatchers(attributesInChildXml).get(3).path() || '''/customer/address/@third_custom_attribute'''
}
@Unroll
def "should remove elements to [#expectedValue] for xPath [#value]"() {
given:
- BodyMatchers m = new BodyMatchers()
- m.xPath(xpath, m.byEquality());
+ BodyMatchers m = new BodyMatchers()
+ m.xPath(xpath, m.byEquality());
expect:
- result == XmlToXPathsConverter.removeMatchingXPaths(xml, m)
+ result == XmlToXPathsConverter.removeMatchingXPaths(xml, m)
where:
- xpath || xml || result
- "/ns1:customer/email/text()" || namedXml || '''\n \n '''
- "/customer/email/text()" || namedXml || '''\n customer@test.com\n '''
- "/customer/email/text()" || unnamedXml || '''\n \n '''
+ xpath || xml || result
+ "/ns1:customer/email/text()" || namedXml || '''\n \n '''
+ "/customer/email/text()" || namedXml || '''\n customer@test.com\n '''
+ "/customer/email/text()" || unnamedXml || '''\n \n '''
+ }
+
+ @Issue("#1546")
+ def "should remove multiple elements when xpath matches them"() {
+ given:
+ String test = '''\
+
+
+ 123
+
+
+ 234
+
+
+'''
+ BodyMatchers m = new BodyMatchers()
+ m.xPath("/root/*/id/text()", m.byEquality());
+ expect:
+ XmlToXPathsConverter.removeMatchingXPaths(test, m) == '''\n \n \n \n \n \n \n'''
}
}