2

I am having troubles with XML matching, which appears to be working a bit differently from JSON.

I found this code snippet

* def xml = <foo><bar>baz</bar></foo>
* set xml/foo/bar = <hello>world</hello>
* match xml == <foo><bar><hello>world</hello></bar></foo>

But with this, I cannot specify that I'm using a template, and that <hello>world</hello> may be present more than once.

Scenario XML 1 is failing, while the others are working.

Scenario: Scenario XML 1

    * def response = <response><foo><bar><msg name="Hello"/><msg name="World"/></bar><bar><msg name="Hello"/><msg name="World"/></bar></foo></response>
    * def bar = <bar><msg name="Hello"/><msg name="World"/></bar>
    * def foo = <response><foo>#[](bar)</foo></response>
    * print foo
    * print response
    * match response == foo

Scenario: Scenario XML 2

    * def response = <response><foo><bar><msg name="Hello"/><msg name="World"/></bar></foo></response>
    * def bar = <bar><msg name="Hello"/><msg name="World"/></bar>
    * def foo = <response><foo>#(bar)</foo></response>
    * print foo
    * print response
    * match response == foo

Scenario: Scenario JSON 1
    * def response = {"response": {"foo": [{"bar": [{"msg": "Hello World"},{"msg": "Hello World"}]}, {"bar": [{"msg": "Hello World"},{"msg": "Hello World"}]}]}}
    * def bar = {"bar": [{"msg": "Hello World"},{"msg": "Hello World"}]}
    * def foo = {"response": {"foo": #[](bar)}}
    * print foo
    * print response
    * match response == foo

Scenario: Scenario JSON 2
    * def response = {"response": {"foo": {"bar": [{"msg": "Hello World"},{"msg": "Hello World"}]}}}
    * def bar = {"bar": [{"msg": "Hello World"},{"msg": "Hello World"}]}
    * def foo = {"response": {"foo": #(bar)}}
    * print foo
    * print response
    * match response == foo

How can I have Scenario XML 1 working?

Adrien
  • 1,080
  • 4
  • 14

1 Answers1

1

I admit this can be considered a gap. The fact that XML repeated elements are so different from JSON doesn't help. The best I could do is this:

* def response = <foo><bar><msg name="Hello"/><msg name="World"/></bar><bar><msg name="Hello"/><msg name="World"/></bar></foo>
* def bar = <bar><msg name="Hello"/><msg name="World"/></bar>
* def foo = <foo>#ignore</foo>
* match response == foo
* match /foo/bar/msg[1]/@name == ['Hello', 'Hello']
* def names = $response/foo/bar/msg[1]/@name
* match each names == 'Hello'

Feel free to submit a feature request and suggest based on your experience with JSON what the ideal syntax should look like.

EDIT: thought about it a little and realized because of how Karate converts XML into JSON-like data internally, you have this option.

* json response = <response><foo><bar><msg name="Hello"/><msg name="World"/></bar><bar><msg name="Hello"/><msg name="World"/></bar></foo></response>
* json bar = <bar><msg name="Hello"/><msg name="World"/></bar>
* match each response.response.foo.bar == bar.bar
* match response == { response: { foo: { bar: '#[] bar.bar' } } }

I know it may be a little hard to understand, but will work :) I was looking at the code right now, and because of how involved the JSON matching is - it is unlikely to get re-factored to support XML repeated elements.

EDIT2: actually we made a fix now so this should be possible also:

* match response == <response><foo><bar>#[] bar.bar</bar></foo></response>

https://github.com/intuit/karate/issues/653

Peter Thomas
  • 54,465
  • 21
  • 84
  • 248
  • Thank you. Would it be possible to handle syntax like #[](bar) inside of XML, in order to translate it to the JSON Schema in karate? This would allow to store the schemas in XML and not in Json, so they would be closer to the real answer and easier to read? – Adrien Jan 18 '19 at 13:28
  • For example, instead of `#[](bar)` being translated to `"foo": { "_": "#[](bar)"}`, have it translate to `"foo": {#[](bar)}`? – Adrien Jan 18 '19 at 13:47
  • @Adrien just made an edit, do you think you can build from source and try: https://github.com/intuit/karate/wiki/Developer-Guide – Peter Thomas Jan 18 '19 at 13:54