Skip to content

Commit 2fcc470

Browse files
committed
rfc: Implement generators for XML text and attribute
1 parent 0caf4db commit 2fcc470

1 file changed

Lines changed: 179 additions & 0 deletions

File tree

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
---
2+
name: implement-generators-for-xml-text-and-attribute
3+
started: 2024-02-10
4+
pr: pact-foundation/roadmap#0000
5+
tracking_issue: pact-foundation/roadmap#0000
6+
---
7+
## Summary
8+
9+
This RFC proposes implementing generators for bodies of type `application/xml`.
10+
11+
## Motivation
12+
13+
Currently if we define generators for text or attribute of XML's body, mock server will return this error:
14+
15+
> Generators are not supported with XML
16+
17+
And there will be an error message in the log:
18+
19+
> UNIMPLEMENTED: Generators are not currently supported with XML
20+
21+
To fix this error, we need to implement generators for XML.
22+
23+
## Guide-level explanation
24+
25+
### Text
26+
27+
To define generator for XML element's text, we can use this JSON format:
28+
29+
```json
30+
{
31+
"name": "release-date",
32+
"children": [
33+
{
34+
"pact:generator:type": "Date",
35+
"matcher": {
36+
"format": "dd-MM-yyyy",
37+
"pact:matcher:type": "date"
38+
},
39+
"content": ""
40+
}
41+
],
42+
"attributes": []
43+
}
44+
```
45+
46+
Mock server should return XML response like this:
47+
48+
```xml
49+
<?xml version='1.0'?><movie><release-date>27-11-2012</release-date></movie>
50+
```
51+
52+
### Attribute
53+
54+
To define generator for XML element's attribute, we can use this JSON format:
55+
56+
57+
```json
58+
{
59+
"name": "specs",
60+
"children": [],
61+
"attributes": {
62+
"runtime": {
63+
"pact:generator:type": "Regex",
64+
"regex": "\\d+ hours [0-5]?[0-9] minutes",
65+
"pact:matcher:type": "regex",
66+
"value": ""
67+
},
68+
"aspect-ratio": {
69+
"pact:generator:type": "Regex",
70+
"regex": "([0-9]+[.])?[0-9]+:[0-9]+",
71+
"pact:matcher:type": "regex",
72+
"value": ""
73+
},
74+
"color": {
75+
"pact:generator:type": "Regex",
76+
"regex": "color|black&white",
77+
"pact:matcher:type": "regex",
78+
"value": ""
79+
}
80+
}
81+
}
82+
```
83+
84+
Mock server should return XML response like this:
85+
86+
```xml
87+
<?xml version='1.0'?><movie><specs runtime='1 hours 23 minutes' aspect-ratio='3:4' color='color'/></movie>
88+
```
89+
90+
## Reference-level explanation
91+
92+
### Implementation
93+
94+
- Begin at root element
95+
- Apply generator for each attribute
96+
- Apply generator for each child element (recursively)
97+
- Apply generator for each child text
98+
- If there are no text & there is generator for text, then generate text and append to the element
99+
100+
### Corner cases
101+
102+
#### Text
103+
104+
- Element has no text
105+
- Generator: `RandomInt(0, 999)`
106+
- Path: `$.a['#text']`
107+
- Before: `<?xml version='1.0'?><a></a>`
108+
- After: `<?xml version='1.0'?><a>123</a>`
109+
- Note: New child text is append to the element
110+
- Element has a child element
111+
- Generator: `RandomInt(0, 999)`
112+
- Path: `$.a['#text']`
113+
- Before: `<?xml version='1.0'?><a><b/></a>`
114+
- After: `<?xml version='1.0'?><a><b/>123</a>`
115+
- Note: New child text is append to the element
116+
- Element has mixed children
117+
- Generator: `RandomInt(0, 999)`
118+
- Path: `$.a['#text']`
119+
- Before: `<?xml version='1.0'?><a><b/>-1</a>`
120+
- After: `<?xml version='1.0'?><a><b/>123</a>`
121+
- Element has multiple texts
122+
- Generator: `RandomInt(0, 999)`
123+
- Path: `$.a['#text']`
124+
- Before: `<?xml version='1.0'?><a>-1<b/>-2</a>`
125+
- After: `<?xml version='1.0'?><a>123<b/>234</a>`
126+
- Note: We can't define index for the text (e.g. can't do this `$.a['#text'][0]` or this `$.a['#text'][1]`), the same generator is applied to every texts
127+
- Multiple elements has text
128+
- Generator: `RandomInt(0, 999)`
129+
- Path: `$.root.a['#text']`
130+
- Before: `<?xml version='1.0'?><root><a>-1</a><a>-2</a></root>`
131+
- After: `<?xml version='1.0'?><root><a>123</a><a>234</a></root>`
132+
- Element has namespace
133+
- Generator: `RandomInt(0, 999)`
134+
- Path: `$.n:a['#text']`
135+
- Before: `<?xml version='1.0'?><n:a xmlns:n='http://example.com/namespace'>-1</n:a>`
136+
- After: `<?xml version='1.0'?><n:a xmlns:n='http://example.com/namespace'>123</n:a>`
137+
- Element has mixed namespace
138+
- Generator: `RandomInt(0, 999)`
139+
- Path: `$.root.n:a['#text']`
140+
- Before: `<?xml version='1.0'?><root><n:a xmlns:n='http://example.com/namespace'>-1</n:a><a>-2</a></root>`
141+
- After: `<?xml version='1.0'?><root><n:a xmlns:n='http://example.com/namespace'>123</n:a><a>-2</a></root>`
142+
143+
144+
#### Attribute
145+
146+
- Attribute has namespace
147+
- Generator: `RandomInt(0, 999)`
148+
- Path: `$.a['@n:attr']`
149+
- Before: `<?xml version='1.0'?><a n:attr='-1' xmlns:n='http://example.com/namespace'/>`
150+
- After: `<?xml version='1.0'?><a n:attr='123' xmlns:n='http://example.com/namespace'/>`
151+
- Attribute has mixed namespace
152+
- Generator: `RandomInt(0, 999)`
153+
- Path: `$.a['@n:attr']`
154+
- Before: `<?xml version='1.0'?><a n:attr='-1' attr='-2' xmlns:n='http://example.com/namespace'/>`
155+
- After: `<?xml version='1.0'?><a n:attr='123' attr='-2' xmlns:n='http://example.com/namespace'/>`
156+
157+
## Drawbacks
158+
159+
None
160+
161+
## Rationale and alternatives
162+
163+
None
164+
165+
## Unresolved questions
166+
167+
None
168+
169+
## Future possibilities
170+
171+
In the future, when we can define index for the text, then we can define different matcher/generator for each text, then we can apply different generator for each text:
172+
173+
- Generators:
174+
- Path: `$.a['#text'][0]`
175+
Generator: `RandomInt(0, 999)`
176+
- Path: `$.a['#text'][1]`
177+
Generator: `RandomString(3)`
178+
- Before: `<?xml version='1.0'?><a>-1<b/>-2</a>`
179+
- After: `<?xml version='1.0'?><a>123<b/>abc</a>`

0 commit comments

Comments
 (0)