XPath conditions in a Logic App

Tanguy SCHOUBERT
Published by Tanguy SCHOUBERT
Category : Azure / Logic Apps
21/09/2020

The requirement: retrieve a specific value from JSON

 

Our Logic App receives this JSON payload as an input:

 

{
  "Product": {
    "@type": "food",
    "Names": [
      {
        "@language": "fr",
        "value": "Farine"
      },
      {
        "@language": "en",
        "value": "Flour"
      }
    ]
  }
}

 

Here, we want to retrieve the product name in a specific language. A number of methods are possible to access this value, including the following:

  • Write a “for each” loop to run through the Names table, and use the Condition shape to check the @language field;
  • Use a Filter Array shape on the Names table with a criterion on @language;
  • Use an XPath expression with a condition on @language.

For this very simple example, all three methods are possible. But for a more complicated situation, it can be beneficial to use XPath so as not to increase the number of shapes.

 

Using the XPath expression

 

To be able to use an XPath expression, the JSON payload first has to be converted into XML. If we try it as it stands, the Logic App displays an error message that XML root nodes cannot have attributes. To avoid this, we embed the Product root node within a new root node. In the Logic App expression:

 

concat('{"root":', triggerbody(), '}')

 

The result obtained:

 

{
  "root": {
    "Product": {
      "@type": "food",
      "Names": [
        {
          "@language": "fr",
          "value": "Farine"
        },
        {
          "@language": "en",
          "value": "Flour"
        }
      ]
    }
  }
}

 

The complete XPath expression is consequently:

 

xpath(xml(json(concat('{"root":', triggerbody(), '}'))), '/*[name()="root"]/*[name()="Product"]/*[name()="Names" and @language="en"]')

 

The result is as follows:

 

[{"$content-type":"application/xml;charset=utf-8","$content":"PE5hbWVzIGxhbmd1YWdlPSJlbiI+DQogIDx2YWx1ZT5GbG91cjwvdmFsdWU+DQo8L05hbWVzPg=="}]

 

We therefore have a JSON table holding our result in a field called $content. To fetch this result:

 

xpath(xml(json(concat('{"root":', triggerbody(), '}'))), '/*[name()="root"]/*[name()="Product"]/*[name()="Names" and @language="en"]')?[0]?['$content']

 

We see the result in XML as it is decoded automatically from base64:

 

<Names language="en">  <value>Flour</value></Names>

 

Lastly, to retrieve the value of the value tag, we convert the result into JSON after explicitly decoding it from base64 then parsing it into XML. Our final expression:

 

json(xml(decodeBase64(xpath(xml(json(concat('{"root":', triggerbody(), '}'))), '/*[name()="root"]/*[name()="Product"]/*[name()="Names" and @language="en"]')?[0]?['$content'])))?['Names']?['value']

 

And our final result:

 

Flour

 

We have reached the desired value using our expression, which is admittedly fairly complex. To improve readability, it is entirely possible to break it down, using variables in our Logic App for example, especially if there is more than one condition to be applied.