4

XPath 3.1 supports a new map feature that allows maps in the result sequences. https://www.w3.org/TR/xpath-31/#id-maps

For example, here is the valid XPath 3.1 expression that returns a hardcoded sequence of 2 maps:

(map {'a':1,'b':2,'c':3}, map {'x':-3,'y':-2,'z':-1})

I am trying to use this feature to collect node attributes as list of maps.

For example, for the given xml:

<root>
  <node a="1" b="2" c="3"/>
  <node x="-3" y="-2" z="-1"/>
</root>

How can I craft a simple XPath expression to get the following result:

[{'a':1,'b':2,'c':3}, {'x':-3,'y':-2,'z':-1}]
yurgis
  • 4,017
  • 1
  • 13
  • 22

1 Answers1

3

With an element as context item you can form a map of the attributes like this:

map:merge(@* ! map{local-name(): string()})

To get a sequence of maps for a sequence of elements $in, you can do

$in ! map:merge(@* ! map{local-name(): string()})

To get an array of maps for a sequence of elements $in, you can do

array { $in ! map:merge(@* ! map{local-name(): string()}) }

In your example you are also converting the attribute values to numbers, so you would use xs:integer(.) in place of string(). But you haven't said what you want to do if there are non-numeric attributes.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
  • I am getting net.sf.saxon.s9api.SaxonApiException: Namespace prefix 'map' has not been declared. Am I missing some configuration? I am using s9api java api and i am calling xpathCompiler.setLanguageVersion("3.1"); – yurgis May 22 '17 at 21:54
  • Nevermind figured i have to call: xpathCompiler.declareNamespace("map", "http://www.w3.org/2005/xpath-functions/map"); Checking the rest of the solution now – yurgis May 22 '17 at 22:03
  • For my needs the following expression was sufficient: ```/root/node/map:merge(@*/map{local-name(): xs:integer(.)})``` Wonder if there is any performance hit of using '/' vs '!'. – yurgis May 23 '17 at 00:16
  • The compiler will work out that if the RHS of "/" isn't going to return nodes, then it can safely replace the "/" by the simpler "!" operator. But I prefer to use "!" to start with, since it better reflects the intent. – Michael Kay May 23 '17 at 08:30