Home > other >  Select part of XML Document by dynamic evaluated XPath test expression
Select part of XML Document by dynamic evaluated XPath test expression

Time:10-13

I am failing with a seemingly simple task.

I have a configuration file which defines different scenarios. Each scenario has a test expression. The idea is, that instructions within the scenario shall be applied to input documents which match the test expression. For example:

<config>
<scenario test="/input/@id eq 'X'">
    ...
</scenario>
<scenario test="/input/@id eq 'Y'">
    ...
</scenario>
</config>

My Problem / Question is: With a given input File, how to identify the matching scenario?

Let $d be a variable with some document node. I can check if it matches the pattern P by writing $d[P]. So i tried with something like

let $p:=doc("config.xml")/config/scenario/@test,
$d:=doc("input.xml")
return $d[$p] 

I expected an non-empty sequence if and only if the input Document $i matches the test Pattern $p. But the result of the expression is never empty, no matter what the @test Attribute is. Even if there is just one scenario with a test expression that definitive does not match.

Thanks in advance, Frank

CodePudding user response:

In your example the variable $p is a sequence of attributes, and when you use that $p in your predicate, it's converted to a boolean value, as if by the boolean() function. The XPath spec says:

If its operand is a sequence whose first item is a node, fn:boolean returns true.

So if your config file has any test scenarios, then the predicate will return true.

What you need to do is evaluate that expression.

CodePudding user response:

XPath evaluation can be done in XSLT 3.0 using xsl:evaluate:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:mf="http://example.com/mf"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:function name="mf:evaluate-predicate" as="item()*">
    <xsl:param name="context-item" as="item()"/>
    <xsl:param name="predicate" as="xs:string"/>
    <xsl:evaluate context-item="$context-item" xpath="'.[' || $predicate || ']'"/>
  </xsl:function>
  
  <xsl:template match="/input[some $pred in $config/config/scenario/@test satisfies mf:evaluate-predicate(., $pred)]">
    <xsl:copy-of select="."/>
  </xsl:template>
  
  <xsl:param name="config" select="doc('config.xml')"/>

</xsl:stylesheet>

xsl:evaluate is an optional feature, it was not supported in early XSLT 3 Saxon HE version (i.e. 9.8 and 9.9) but is supported in Saxon HE 10 and 11 (and of course in PE/EE since 9.8). It is also supported in SaxonJS 2.

  • Related