WireMock-Net / WireMock.Net

WireMock.Net is a flexible product for stubbing and mocking web HTTP responses using advanced request matching and response templating. Based on the functionality from http://WireMock.org, but extended with more functionality.
Apache License 2.0
1.36k stars 200 forks source link

Loop through xml elements in handlebars template #970

Closed rmeshksar closed 11 months ago

rmeshksar commented 11 months ago

I have a request with XML body. In the response template, I would like to loop through some of the elements of the request and add new elements to the response. XPath.SelectNodes helpers returns a string and I cannot use {{#each method on it.

Wondering if there is any way to do it?

Maybe adding a new Handlebars helper?

StefH commented 11 months ago

The SelectNodes does always return a string, which is not very usable.

I'll update https://github.com/Handlebars-Net/Handlebars.Net.Helpers to return a list which can be used in an each.

StefH commented 11 months ago

https://github.com/Handlebars-Net/Handlebars.Net.Helpers/pull/80

StefH commented 11 months ago

@rmeshksar I've updated the https://github.com/Handlebars-Net/Handlebars.Net.Helpers

So for this XML:

<?xml version='1.0' standalone='no'?>
<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:ns=""http://www.Test.nl/XMLHeader/10"">
   <soapenv:Header>
      <ns:TestHeader>
         <ns:HeaderVersion>10</ns:HeaderVersion>
      </ns:TestHeader>
   </soapenv:Header>
   <soapenv:Body>
      <req>
         <TokenIdLijst>
            <TokenId>0000083256</TokenId>
            <TokenId>0000083259</TokenId>
         </TokenIdLijst>
      </req>
   </soapenv:Body>
</soapenv:Envelope>;

And this C# code:

[Fact]
    public void SelectNodes_InEachLoop()
    {
        // Arrange
        var request = new
        {
            body = MiniTestSoapMessage
        };

        var expression = "{{#each (XPath.SelectNodes body \"//*[local-name()='TokenId']/text()\")}}\r\n{{this}}\r\n{{/each}}";
        var action = _handlebarsContext.Compile(expression);

        // Act
        var result = action(request);

        // Assert
        result.Should().Be("0000083256\r\n0000083259\r\n");
    }

Returns this: "0000083256\r\n0000083259\r\n"

I think this is what you need? Can you comment ?

rmeshksar commented 11 months ago

This is exactly what I was looking for. Thanks for the quick response.

For now I did something by splitting the string and loop through that but I will use this much much better approach when it is released.

{{#each (String.Split (String.Replace (XPath.SelectNodes request.body '//TokenIdLijst/TokenId') "/TokenId>" "/TokenId>*******") "*******")}}

{{this}}

{{/each}}
rmeshksar commented 11 months ago

I also would like to ask another question here: XPath.Evaluate returns an object and not string. It is working fine if I use it directly in the template as ToString method returns the Value.

But I cannot use it with another string function like Uppercase.

What do you suggest?

StefH commented 11 months ago

I can add a method EvaluateToString ?

rmeshksar commented 11 months ago

That would be great. Evaluate can return an array. In fact I think what is returns is IEnumerable\<XPathItem>.

Evaluate("<x><a id=\"1\"></a></x>", "//a/@id").ToString().Dump(); // <-- 1
Evaluate("<x><a id=\"1\"></a><a id=\"2\"></a></x>", "//a/@id").ToString().Dump(); // <-- 1, 2
rmeshksar commented 11 months ago

Maybe also a ToString() helper is a good addition to the helpers.

StefH commented 11 months ago

EvaluateToString has been added, see PR.

ToString() helper is a good addition to the helpers. yes I thought on that, but this requires a change in many helpers, so for now I'll skip this.

StefH commented 11 months ago

In the next days I will create a new NuGet for Handlebars.Net.Helpers and I'll include this in WireMock.Net

rmeshksar commented 11 months ago

This is amazing. Thanks

StefH commented 11 months ago

https://github.com/WireMock-Net/WireMock.Net/pull/976