XML * XML-SCHEMA * XPATH * XSL * XSL-FO * SVG * XQUERY * XPROC * ANT * DIVERSES



XPath / XPath-Operatoren / Logische Operatoren

Logische Operatoren

Logische Operatoren

➪ Logische Operatoren erlauben allgemeine Vergleichs- sowie Verknüpfungsoperationen wie <, <=, >, >=, =, !=, and, or oder not.

< kleiner als. Bei Verwendung im XSL-Umfeld ist eine Konvertierung von "<" in "&lt;" erforderlich.
<= kleiner oder gleich. Hier ist ggf. eine Konvertierung in &lt;= erforderlich.
> größer als. Hier ist eine Konvertierung in &gt; erforderlich.
>= größer oder gleich. Hier ist eine Konvertierung in &gt;= erforderlich.
= ist gleich.
!= ist nicht gleich. Beispiel: <xsl:if test="position() != last()"> ...
and und. Verknüpft mehrere Bedingungen.
or oder
not() nicht

Statt der Arbeit mit and kann eine Verwendung von Prädikaten sinnvoll sein. Statt


<xsl:for-each 
     select="//Mensch[Gehalt &gt; 500 and Gehalt &lt; 1000]"> 

... können Sie auch schreiben ...


<xsl:for-each 
     select="//Mensch[Gehalt &gt; 500][Gehalt &lt; 1000]">

Wie schon bei den nummerischen Operatoren kann die Arbeit mit Boolean-Tests fehlerhaft werden, etwa wenn zwei Zahlen miteinander verglichen werden und im Hintergrund automatisch ein Type-Cast auf den Datentyp double läuft.


  <xsl:variable name="v1">2.1</xsl:variable>
  <xsl:variable name="v2">3</xsl:variable>
  <ergebnis>
    <xsl:if test="($v1 * $v2) != 6.3">
      <Fehler1 erwartet="6.3">
        <xsl:value-of select="$v1 * $v2" />
      </Fehler1>
    </xsl:if>
    <xsl:if test="($v1 * $v2) &lt; 6.3">
      <Fehler2 erwartet="6.3">
        <xsl:value-of select="$v1 * $v2" />
      </Fehler2>
    </xsl:if>
    <xsl:if test="($v1 * $v2) &gt; 6.3">
      <Fehler3 erwartet="6.3">
        <xsl:value-of select="$v1 * $v2" />
      </Fehler3>
    </xsl:if>
    <xsl:if test="($v1 * $v2) = 6.3">
      <ALLES_OK erwartet="6.3">
        <xsl:value-of select="$v1 * $v2" />
      </ALLES_OK>
    </xsl:if>
  </ergebnis>

In diesem Beispiel erhalten Sie die Ausgabe für die Fehler1 und Fehler3:


<ergebnis>
  <Fehler1 erwartet="6.3">6.300000000000001</Fehler1>
  <Fehler3 erwartet="6.3">6.300000000000001</Fehler3>
</ergebnis>

Ein anderer Prozessor liefert die folgenden Ergebnisse:


<ergebnis>
  <Fehler1 erwartet="6.3">6.3000000000000007</Fehler1>
  <Fehler3 erwartet="6.3">6.3000000000000007</Fehler3>
</ergebnis>

Bemerkenswert (und nur auf den ersten Blick amüsant) fand ich das Ergebnis, das ich mit wieder einem anderen für XSL 1.0, 2.0 und 3.0 erhalten habe:


<ergebnis>
  <Fehler1 erwartet="6.3">6.3</Fehler1>
  <Fehler3 erwartet="6.3">6.3</Fehler3>
</ergebnis>

Würden Sie dagegen die beiden Variablen v1 und v2 auf den Datentyp xs:decimal casten ...


 <xsl:variable name="v1" as="xs:decimal">2.1</xsl:variable>
 <xsl:variable name="v2" as="xs:decimal">3</xsl:variable>

... so wäre das Ergebnis weit ergiebiger:


<ergebnis>
  <ALLES_OK erwartet="6.3">6.3</ALLES_OK>
</ergebnis>

Das ist nicht mehr trivial. Wenn ein Zahlenvergleich (aus teilweise berechneten Werten) grundverschiedene Konsequenzen nach sich zieht, dann müssen Sie sich auch darauf verlassen können, dass das System korrekt arbeitet. Das ist aber nicht zweifelsfrei sichergestellt, wenn eine scheinbar harmlose Rechenoperation suboptimale interne Algorithmen verwendet, die das Ergebnis verfälschen und in der Folge Fehlentscheidungen nach sich ziehen könnten.

Die Abweichungen zwischen xs:double und xs:decimal werden deutlich bei einem einfachen Vergleich, in dem zwei Schleifen ineinanderlaufen und die Werte in Variablen unterschiedlichen Typs casten.

Der hier erzwungene Type-Cast dient auch zur Verdeutlichung, dass der Prozessor-interne Type-Cast dem Programmierer möglicherweise nicht bewusst ist. Wenn der Type-Cast für xs:double für vzdouble und vsdouble entfernt wird, ergibt sich kein Fehler, im Gegensatz zu der vorher dargestellten Logik.


<ergebnis>
 <xsl:for-each select="1 to 10">
  <xsl:variable name="vzdouble" 
       select=". div 10" as="xs:double" />
  <xsl:variable name="vzdecimal" 
       select="(xs:decimal(.) div 10)" as="xs:decimal" />
  <xsl:for-each select="1 to 10">
   <xsl:variable name="vsdouble" 
        select="." as="xs:double" />
   <xsl:variable name="vsdecimal" 
        select="xs:decimal(.)" as="xs:decimal" />
   <xsl:if test="($vzdouble * $vsdouble) != ($vzdecimal * $vsdecimal)">
    <Differenz z="{$vzdouble}" s="{$vsdouble}" 
     ergdouble="{$vzdouble * $vsdouble}"
     ergdecimal="{$vzdecimal * $vsdecimal}" />
   </xsl:if>
  </xsl:for-each>
 </xsl:for-each>
</ergebnis>

Dieser vergleichsweise sehr bescheidene Ansatz von lediglich 10 x 10 = 100 Wertekombinationen ergibt immerhin 21 Abweichungen. Das bedeutet eine Abweichungs-Quote von gut zwanzig Prozent. Für mich ist das ein hinreichender Grund, sich etwas näher mit dem Type-Casting und also mit XSLT 2.0 zu befassen.


  <ergebnis>
   <Differenz z="0.1" s="3" 
           ergdouble="0.30000000000000004" 
           ergdecimal="0.3"/>
   <Differenz z="0.1" s="6" 
           ergdouble="0.6000000000000001" 
           ergdecimal="0.6"/>
   <Differenz z="0.1" s="7" 
           ergdouble="0.7000000000000001" 
           ergdecimal="0.7"/>
   <Differenz z="0.2" s="3" 
           ergdouble="0.6000000000000001" 
           ergdecimal="0.6"/>
   <Differenz z="0.2" s="6" 
           ergdouble="1.2000000000000002" 
           ergdecimal="1.2"/>
   <Differenz z="0.2" s="7" 
           ergdouble="1.4000000000000001" 
           ergdecimal="1.4"/>
   <Differenz z="0.3" s="3" 
           ergdouble="0.8999999999999999" 
           ergdecimal="0.9"/>
   <Differenz z="0.3" s="6" 
           ergdouble="1.7999999999999998" 
           ergdecimal="1.8"/>
   <Differenz z="0.3" s="9" 
           ergdouble="2.6999999999999997" 
           ergdecimal="2.7"/>
   <Differenz z="0.4" s="3" 
           ergdouble="1.2000000000000002" 
           ergdecimal="1.2"/>
   <Differenz z="0.4" s="6" 
           ergdouble="2.4000000000000004" 
           ergdecimal="2.4"/>
   <Differenz z="0.4" s="7" 
           ergdouble="2.8000000000000003" 
           ergdecimal="2.8"/>
   <Differenz z="0.6" s="3" 
           ergdouble="1.7999999999999998" 
           ergdecimal="1.8"/>
   <Differenz z="0.6" s="6" 
           ergdouble="3.5999999999999996" 
           ergdecimal="3.6"/>
   <Differenz z="0.6" s="9" 
           ergdouble="5.3999999999999995" 
           ergdecimal="5.4"/>
   <Differenz z="0.7" s="3" 
           ergdouble="2.0999999999999996" 
           ergdecimal="2.1"/>
   <Differenz z="0.7" s="6" 
           ergdouble="4.199999999999999" 
           ergdecimal="4.2"/>
   <Differenz z="0.7" s="7" 
           ergdouble="4.8999999999999995" 
           ergdecimal="4.9"/>
   <Differenz z="0.8" s="3" 
           ergdouble="2.4000000000000004" 
           ergdecimal="2.4"/>
   <Differenz z="0.8" s="6" 
           ergdouble="4.800000000000001" 
           ergdecimal="4.8"/>
   <Differenz z="0.8" s="7" 
           ergdouble="5.6000000000000005" 
           ergdecimal="5.6"/>
  </ergebnis>

wg / 9. Mai 2020



Fragen? Anmerkungen? Tipps?

Bitte nehmen Sie Kontakt zu mir auf.






Vielen Dank für Ihr Interesse an meiner Arbeit.



V.i.S.d.P.: Wilfried Grupe * Klus 6 * 37643 Negenborn

☎ 0151. 750 360 61 * eMail: info10@wilfried-grupe.de

www.wilfried-grupe.de/XPath_Operatoren2.html