0

So I have an XML that looks a bit like this in an object variable:

<root>
    <assetRegistration>Value</assetRegistration>
    <assetName>Value</assetName>
    <assetId>Value</assetId>
    <driverId>Value</driverId>
    <driverName>Value</driverName>
    <driverGroupId>Value</driverGroupId>
    <driverGroupName>Value</driverGroupName>
    <assetGroupId>Value</assetGroupId>
    <assetGroupName>Value</assetGroupName>
</root>

I am trying to use the XPath function in another variable to get all of the element names inside the root element. I have used many different expressions in the XPath function without any luck.

Here is an example:

xpath(variables('testXML'), '//*/*[name()]')

But this just returns an array with this sort of thing in it:

[
  {
    "$content-type": "application/xml;charset=utf-8",
    "$content": "PGFzc2V0UmVnaXN0cmF0aW9uPkxGNjFYR088L2Fzc2V0UmVnaXN0cmF0aW9uPg=="
  },
  {
    "$content-type": "application/xml;charset=utf-8",
    "$content": "PGFzc2V0TmFtZT5Vbmtub3duPC9hc3NldE5hbWU+"
  },
  {
    "$content-type": "application/xml;charset=utf-8",
    "$content": "PGFzc2V0SWQ+NjA0MjY0PC9hc3NldElkPg=="
  },
  {
    "$content-type": "application/xml;charset=utf-8",
    "$content": "PGRyaXZlcklkPjE0MzM0MDwvZHJpdmVySWQ+"
  },
  {
    "$content-type": "application/xml;charset=utf-8",
    "$content": "PGRyaXZlck5hbWU+TWljaGFlbCBDYW1wYmVsbDwvZHJpdmVyTmFtZT4="
  },
  {
    "$content-type": "application/xml;charset=utf-8",
    "$content": "PGRyaXZlckdyb3VwSWQ+NTUwNmViMDhlNGIwYjc5YTEwMzY4NWNmPC9kcml2ZXJHcm91cElkPg=="
  },
  {
    "$content-type": "application/xml;charset=utf-8",
    "$content": "PGRyaXZlckdyb3VwTmFtZT5Fc3NleCBMaWdodGluZzwvZHJpdmVyR3JvdXBOYW1lPg=="
  },
  {
    "$content-type": "application/xml;charset=utf-8",
    "$content": "PGFzc2V0R3JvdXBJZD41MjhiODQ3ZGE3ZjQ3ZWRiYmE0NTQyYWU8L2Fzc2V0R3JvdXBJZD4="
  },
  {
    "$content-type": "application/xml;charset=utf-8",
    "$content": "PGFzc2V0R3JvdXBOYW1lPkRlLUZpdHRlZDwvYXNzZXRHcm91cE5hbWU+"
  },
  {
    "$content-type": "application/xml;charset=utf-8",
    "$content": "PGRhdGU+MjAxNi0wMi0wOVQwNjozNzo0NjwvZGF0ZT4="
  },
  {
    "$content-type": "application/xml;charset=utf-8",
    "$content": "PHN0YXR1cz5lbmRPZkpvdXJuZXk8L3N0YXR1cz4="
  },
  {
    "$content-type": "application/xml;charset=utf-8",
    "$content": "PGV2ZW50VHlwZT5zdG9wcGVkPC9ldmVudFR5cGU+"
  }
]

Others just return an empty array.

Thanks for any help with this.

I've tried the following XPath expressions as well as others:

'name(/root/*)'
'//*[not(*)]/*[name()]'
'//root/*[not(*)]/*[name()]'
'/root/*/name()'
'/root/*[name()]'
'//root/*[name()]'

I'm expecting an string array of element names. Some of these seem to work in the following link: https://www.freeformatter.com/xpath-tester.html

  • In XPath 2 and later you can indeed use e.g. `//*/name()` to get a sequence of element names. But as you are using Microsoft Azure and Microsoft on no platform has ever delivered any XPath 2 implementation I rather doubt you can use XPath 2 there. I don't know what other options you have, Microsoft, for .NET and XML decided to provide LINQ to XML to its users instead of implementing XPath 2.0 and/or XQuery 1 or later and/or XSLT 2 or later. So on a Microsoft platform LINQ to XML is more likely to be an option for such a task that requires XPath 2.0 or XQuery 1.0. – Martin Honnen Jun 13 '23 at 16:06

1 Answers1

1

Well, one of the expressions you tried is correct:

/root/*/name()

will return all of the element names of all children of the <root> element. Unfortunately this is an XPath 2.0 expression, and as it seems Azure only supports XPath 1.0. Hence it failed and you need another approach.

All XPath expression containing *[name()] are useless, because they are only checking if there is an element containing a non-empty name - which is always the case - because elements require a non-empty name, which is trivial.

So in XSLT-1.0 (using XPath 1.0) the solution is iterating over the elements of the expression /root/* and then accessing the name of the result. It is a two-step procedure:

<xsl:for-each select="/root/*">
  <xsl:value-of select="name()" />  <!-- Get the name() of the current element -->
  <xsl:text>&#xa;</xsl:text>        <!-- Just for line breaks -->
</xsl:for-each>

I do not know how to achieve this in Azure, but I guess that it's a two-step procedure as well:

  1. Get all children of /root
  2. Extract the name() of each child
zx485
  • 28,498
  • 28
  • 50
  • 59
  • Thanks for the response @zx485. I created a `For each` action and used `xpath(variables('testXML'), '/root/*')` as the items of the loop, which returned something like `Value` on the first iteration and in the loop I added a `Set variable` action with `xpath(item(), 'name(//*[1])')` as the Value function, and it returned 'assetRegistration' as a string. – Christopher Page Jun 13 '23 at 19:32
  • Glad that it worked. You can give the shorter version of your second XPath a try: `xpath(item(), 'name()')`. Maybe this works. – zx485 Jun 13 '23 at 19:42
  • Hi @zx485. I tried `xpath(item(), 'name()')` but it didn't work. – Christopher Page Jun 16 '23 at 10:45