Files
Marcin Grzejszczak 0159bcde09 Updated antora docs
2023-09-14 15:43:24 +02:00

124 lines
4.3 KiB
Plaintext

[[contract-dsl-xml]]
== XML Support for HTTP
include::partial$_attributes.adoc[]
For HTTP contracts, we also support using XML in the request and response body.
The XML body has to be passed within the `body` element
as a `String` or `GString`. Also, body matchers can be provided for
both the request and the response. In place of the `jsonPath(...)` method, the `org.springframework.cloud.contract.spec.internal.BodyMatchers.xPath`
method should be used, with the desired `xPath` provided as the first argument
and the appropriate `MatchingType` as the second argument. All the body matchers apart from `byType()` are supported.
The following example shows a Groovy DSL contract with XML in the response body:
====
[source,groovy,indent=0,subs="verbatim",role="primary"]
.Groovy
----
include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/XmlMethodBodyBuilderSpec.groovy[tags=xmlgroovy]
----
[source,yml,indent=0,subs="verbatim",role="secondary"]
.YAML
----
include::{verifier_root_path}/src/test/resources/yml/contract_rest_xml.yml[indent=0]
----
[source,java,indent=0,subs="verbatim",role="secondary"]
.Java
----
include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_xml.java[tags=class,indent=0]
----
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
.Kotlin
----
include::{verifier_root_path}/src/test/resources/kotlin/contract_xml.kts[tags=class,indent=0]
----
====
The following example shows an automatically generated test for XML in the response body:
====
[source,java,indent=0]
----
@Test
public void validate_xmlMatches() throws Exception {
// given:
MockMvcRequestSpecification request = given()
.header("Content-Type", "application/xml");
// when:
ResponseOptions response = given().spec(request).get("/get");
// then:
assertThat(response.statusCode()).isEqualTo(200);
// and:
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance()
.newDocumentBuilder();
Document parsedXml = documentBuilder.parse(new InputSource(
new StringReader(response.getBody().asString())));
// and:
assertThat(valueFromXPath(parsedXml, "/test/list/elem/text()")).isEqualTo("abc");
assertThat(valueFromXPath(parsedXml,"/test/list/elem[2]/text()")).isEqualTo("def");
assertThat(valueFromXPath(parsedXml, "/test/duck/text()")).matches("[0-9]\{3}");
assertThat(nodeFromXPath(parsedXml, "/test/duck/xxx")).isNull();
assertThat(valueFromXPath(parsedXml, "/test/alpha/text()")).matches("[\\p\{L}]*");
assertThat(valueFromXPath(parsedXml, "/test/*/complex/text()")).isEqualTo("foo");
assertThat(valueFromXPath(parsedXml, "/test/duck/@type")).isEqualTo("xtype");
}
----
====
[[xml-support-for-namespaces]]
=== XML Support for Namespaces
Namespaced XML is supported. However, any XPath expresssions used to select namespaced content must be updated.
Consider the following explicitly namespaced XML document:
[source,xml,indent=0]
----
<ns1:customer xmlns:ns1="http://demo.com/customer">
<email>customer@test.com</email>
</ns1:customer>
----
The XPath expression to select the email address is: `/ns1:customer/email/text()`.
WARNING: Beware as the unqualified expression (`/customer/email/text()`) results in `""`.
For content that uses an unqualified namespace, the expression is more verbose. Consider the following XML document that
uses an unqualified namespace:
[source,xml,indent=0]
----
<customer xmlns="http://demo.com/customer">
<email>customer@test.com</email>
</customer>
----
The XPath expression to select the email address is
```
*/[local-name()='customer' and namespace-uri()='http://demo.com/customer']/*[local-name()='email']/text()
```
WARNING: Beware, as the unqualified expressions (`/customer/email/text()` or `*/[local-name()='customer' and namespace-uri()='http://demo.com/customer']/email/text()`)
result in `""`. Even the child elements have to be referenced with the `local-name` syntax.
[[general-namespaced-node-expression-syntax]]
==== General Namespaced Node Expression Syntax
- Node using qualified namespace:
```
/<node-name>
```
- Node using and defining an unqualified namespace:
```
/*[local-name=()='<node-name>' and namespace-uri=()='<namespace-uri>']
```
NOTE: In some cases, you can omit the `namespace_uri` portion, but doing so may lead to ambiguity.
- Node using an unqualified namespace (one of its ancestor's defines the xmlns attribute):
```
/*[local-name=()='<node-name>']
```