Re: [xsl] Compare logical expressions with XPath/XSLT

Subject: Re: [xsl] Compare logical expressions with XPath/XSLT
From: "Michael Kay mike@xxxxxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Thu, 7 Mar 2019 21:10:53 -0000
Here's a refinement of this approach

(a) translate the expressions into XPath syntax ("A AND !B" ==> "$a and
not($b)")

(b) evaluate something like

if (some $a in (true(), false()), $b in (true(), false()), $c in (true(),
false())
    satisfies eval(X, $a, $b, $c) and not eval(Y, $a, $b, $c))
then ....

where eval() invokes xsl:evaluate with appropriate parameters.

This basically differs from David Carlisle's approach in two ways:

(i) enumerating the truth tables is done incrementally without actually
storing the result in a variable

(ii) the boolean expression is compiled into XPath rather than being
interpreted.


Michael Kay
Saxonica



> On 7 Mar 2019, at 20:52, David Carlisle d.p.carlisle@xxxxxxxxx
<xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:
>
> if I understood you correctly you have a fixed number of boolean
> variables (3 here) so you can enumerate the truth table of  each
> project and want to know that the expression for the sub project is
> never true if the expression for the main project is false.
>
> this is not, to put it mildly, well tested but I get
>
> $ saxon9 -it:main prg.xsl
> project 1 and 2
> false
> project 1 and 3
> true
>
>
> from the following which assumes AND and OR always have exactly two
> children and that my typing is accurate, neither of which assumption
> may be true...
>
> <xsl:stylesheet version="2.0"
>        xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
>        xmlns:xs="http://www.w3.org/2001/XMLSchema";
>        xmlns:f="data:,f">
>
> <xsl:variable name="defs" as="element()">
>  <defs>
>  <def name="project-1">
>    <set>
>      <AND>
>        <OR>
>          <item required="false">A</item>
>          <item required="false">B</item>
>        </OR>
>        <item required="false">C</item>
>      </AND>
>    </set>
>  </def>
>  <def name="project-2">
>    <set>
>      <OR>
>        <item required="true">A</item>
>        <item required="true">C</item>
>      </OR>
>    </set>
>  </def>
>  <def name="project-3">
>    <set>
>      <item required="false">C</item>
>    </set>
>  </def>
> </defs>
> </xsl:variable>
>
> <xsl:template name="main">
> <xsl:message select="'project 1 and 2'"/>
> <xsl:message
select="f:check($defs/def[@name='project-1']/set/*,$defs/def[@name='project-2
']/set/*)"/>
> <xsl:message select="'project 1 and 3'"/>
> <xsl:message
select="f:check($defs/def[@name='project-1']/set/*,$defs/def[@name='project-3
']/set/*)"/>
> </xsl:template>
>
> <xsl:function name="f:check" as="xs:boolean">
> <xsl:param name="p1" as="element()"/>
> <xsl:param name="p2" as="element()"/>
> <xsl:variable name="tt1" as="xs:boolean*">
>  <xsl:sequence select="
>  for $a in (true(),false()),$b in (true(),false()),$c in (true(),false())
>  return
>  f:eval($p1,$a,$b,$c)
>  "/>
> </xsl:variable>
> <xsl:variable name="tt2" as="xs:boolean*">
>  <xsl:sequence select="
>  for $a in (true(),false()),$b in (true(),false()),$c in (true(),false())
>  return
>  f:eval($p2,$a,$b,$c)
>  "/>
> </xsl:variable>
> <xsl:variable name="x" as="xs:boolean*">
>  <xsl:for-each select="$tt1">
>   <xsl:variable name="pn" select="position()"/>
>   <xsl:sequence select="not(.) or $tt2[$pn]"/>
>  </xsl:for-each>
> </xsl:variable>
> <xsl:sequence select="every $i in $x satisfies $i"/>
> </xsl:function>
>
> <xsl:function name="f:eval" as="xs:boolean">
> <xsl:param name="p" as="element()"/>
> <xsl:param name="a" as="xs:boolean"/>
> <xsl:param name="b" as="xs:boolean"/>
> <xsl:param name="c" as="xs:boolean"/>
> <xsl:choose>
>  <xsl:when test="$p/self::item[.='A']">
>   <xsl:sequence select="if($p/@required='true') then $a else not($a)"/>
>  </xsl:when>
>  <xsl:when test="$p/self::item[.='B']">
>   <xsl:sequence select="if($p/@required='true') then $b else not($b)"/>
>  </xsl:when>
>  <xsl:when test="$p/self::item[.='C']">
>   <xsl:sequence select="if($p/@required='true') then $c else not($c)"/>
>  </xsl:when>
>  <xsl:when test="$p/self::AND">
>   <xsl:sequence select="f:eval($p/*[1],$a,$b,$c) and
> f:eval($p/*[2],$a,$b,$c)"/>
>  </xsl:when>
>  <xsl:when test="$p/self::OR">
>   <xsl:sequence select="f:eval($p/*[1],$a,$b,$c) or
f:eval($p/*[2],$a,$b,$c)"/>
>  </xsl:when>
>  <xsl:otherwise>
>   <xsl:sequence select="false()(:shouldn't happen:)"/>
>  </xsl:otherwise>
> </xsl:choose>
> </xsl:function>
>
> </xsl:stylesheet>

Current Thread