Testing an Expression by Using Boolean Functions

MSXML 5.0 SDK

Microsoft XML Core Services (MSXML) 5.0 for Microsoft Office - XPath Developer's Guide

Testing an Expression by Using Boolean Functions

The XPath Boolean functions return simple true or false values based on the functions' evaluation of arguments (if any) passed to them.

In the following table, which summarizes the Boolean functions, str represents a string passed as an argument; obj, an object of some arbitrary type, such as node-set or number; and boolean, a Boolean condition (with either a true or false value).

Format Description/Example
boolean(obj) Used primarily to test whether or not something "exists." If obj is a node-set, the function returns true if and only if the node-set is not empty; if a string, if and only if the string's length is greater than 0; and if a number, if and only if it is non-zero and a valid number. In all other cases it returns false.
not(boolean) Returns true if the argument passed to it is false, or false if the argument passed to it is true.
true() Simply returns the value true.
false() Simply returns the value false.
lang(str) Returns true or false, depending on whether or not the context node has the xml:lang value specified in str.

Note   The true() and false() functions generally make explicit what is otherwise implicit in an XPath expression. This is useful primarily for ensuring that your meaning is clear, as in the following:
<xsl:if test="(x=y)=true()">
which could also be represented, more simply:
<xsl:if test="x=y">
However, these two functions may also be used to assign Boolean values to XSLT variables. Examples of this use are shown below.

boolean(obj)

To verify that the value of the <units> element is a number before performing some numeric operation on it, you could use the following:

<xsl:if test="boolean(number(units))">

If the <units> element is empty or contains a non-numeric value, the body of the <xsl:if> element will not be executed.

Note   The preceding is not the same as:
<xsl:if test="boolean(units)">
This simpler test passes the <units> element as a node-set (not its value as a number) to the function, and thus simply verifies that the context node has at least one <units> child.

not(boolean)

The following expression determines whether the document has any <amount> elements whose values are greater than 20,000:

not(amount[. &gt; 20000])

If there are any such <amount> elements, the function returns false, otherwise true.

The not() function appearing in a predicate or XSLT test can sometimes be used interchangeably with the != Boolean operator. For example:

[not("A"="B")]

and

["A"!="B"]

are functionally equivalent.

However, when one of the two values being compared is a node-set, using the not() function vs. the != operator can produce different results, as shown in the sample below.

Consider the two XSLT <xsl:if> elements in the sample XSLT template rule shown below.

The first test outputs "Not March 03" for both invoices. Essentially, it asks the question: "Does the context node have an invoice_date attribute, and if it does, does the attribute's value not equal '2001-03-04'?"

The second outputs "Not March 03" for invoice #X00456 only, because it asks a slightly different question: "Does the context node not have an invoice_date attribute which equals '2001-03-04?" The answer to that question is true for only the <sale> element whose invoice number is X00456.

For more information about the != operator, see Testing within a Predicate by Using Boolean Operators.

Example

XML File (funcnot.xml)

<?xml version='1.0'?>
<?xml-stylesheet type="text/xsl" href="funcnot.xsl" ?>
<sales copyright="2001">
   <sale invoice="X00123" invoice_date="2001-01-05"/>
   <sale invoice="X00456"/>
</sales>

XSLT File (funcnot.xsl)

<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:template match="sales">
   <xsl:for-each select="sale">
      <p><b>For invoice #<xsl:value-of select="@invoice"/></b></p>
      <xsl:if test="@invoice_date!='2001-03-04'">
         <p>Test with "!=": Not March 03</p>
      </xsl:if>
      <xsl:if test="not(@invoice_date='2001-03-04')">
         <p>Test with "not()": Not March 03</p>
      </xsl:if>
   </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

Formatted Output

For invoice #X00123
Test with "!=": Not March 03
Test with "not()": Not March 03
For invoice #X00456
Test with "not()": Not March 03

Processor Output

The XSLT produces the following stream. Line breaks have been added for clarity.

<?xml version="1.0" encoding="UTF-16"?>
<p><b>For invoice #X00123</b></p>
<p>Test with "!=": Not March 03</p>
<p>Test with "not()": Not March 03</p>
<p><b>For invoice #X00456</b></p>
<p>Test with "not()": Not March 03</p>

true() and false()

You can define a variable which returns a true or false value depending on some condition in the document being processed, as in the example below.

The explicit test of the string value "true" in the <xsl:if> element above is necessary because the <xsl:value-of> element in the $units_gt_300 variable's definition returns a result tree fragment (RTF), which—regardless of the actual data type of the RTF's value—is always treated as a string. If we hadn't been concerned with demonstrating the use of the true() and false() functions, the variable's definition could be more concisely expressed as:

<xsl:variable name="units_gt_300" select="number(units) &gt; 300"/>

This would have returned a pure Boolean true or false value. So the <xsl:if> element could more simply have been coded:

<xsl:if test="$units_gt_300">

For more information, see Introduction to Result Tree Fragments.

Example

XML File (xpathfuncs.xml)

Change the href attribute in xpathfuncs.xml (shown in Sample XML Data File for XPath Functions) to reference the above XSLT file.

XSLT File (functruefalse.xsl)

<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:template match="sales">
    <h2>Regions Selling More than 300 Units:</h2>
    <xsl:for-each select="region">
    <xsl:variable name="units_gt_300">
        <xsl:choose>
            <xsl:when test="number(units) &gt; 300">
                <xsl:value-of select="true()"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="false()"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:variable>
    <xsl:if test="$units_gt_300='true'">
        <h3><xsl:value-of select="concat(@name, ' (', units, ' units)')"/></h3>
    </xsl:if>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

Formatted Output

Processor Output

<?xml version="1.0" encoding="UTF-16"?>
<h2>Regions Selling More than 300 Units:</h2>
<h3>Northeast (374 units)</h3>
<h3>Southeast (512 units)</h3>
<h3>Northwest (465 units)</h3>

lang(str)

Consider an XML document such as the following:

<?xml version='1.0'?>
<dict>
    <translate>
        <word xml:lang="DE">Ma&#xDF;einheiten</word>
        <word xml:lang="EN">units</word>
        <word xml:lang="ES">unidades</word>
        <word xml:lang="FR">unit&#xE9;s</word>
        <word xml:lang="IT">unit&#xE8;</word>
        <word xml:lang="PT">unidades</word>
    </translate>
    <translate>
        <word xml:lang="DE">Verk&#xE4;ufe</word>
        <word xml:lang="EN">sales</word>
        <word xml:lang="ES">ventas</word>
        <word xml:lang="FR">ventes</word>
        <word xml:lang="IT">vendite</word>
        <word xml:lang="PT">vendas</word>
    </translate>
</dict>

An XSLT style sheet to demonstrate a general-purpose translation feature might accept two parameters from the user: a word to be translated (held in the parameter called $xlate_word), and a two-character code for the language into which the word is to be translated (the parameter $xlate_lang). Such a style sheet might contain the template rule shown in the sample below.

The template rule's <xsl:for-each> element extracts the <word> element which matches the input word. It then displays the following:

  • The input word
  • The language code which corresponds to the input word
  • The input language code
  • The translated value

Note that the translated value is derived (in the final <xsl:select>) first by locating the parent of the <word> element whose value matches the input word, then by locating the child of that parent whose xml:lang attribute matches the input language code.

With the word "units" and the language code "DE" passed as parameters into the style sheet, Internet Explorer displays this template rule's results as follows:

Input word is: units
Its language code is: EN
Translating to DE...
Translated value is: Maßeinheiten

Example

XML File (funclang.xml)

<?xml version='1.0'?>
<?xml-stylesheet type="text/xsl" href="funclang.xsl" ?>
<dict>
    <translate>
        <word xml:lang="DE">Ma&#xDF;einheiten</word>
        <word xml:lang="EN">units</word>
        <word xml:lang="ES">unidades</word>
        <word xml:lang="FR">unit&#xE9;s</word>
        <word xml:lang="IT">unit&#xE8;</word>
        <word xml:lang="PT">unidades</word>
    </translate>
    <translate>
        <word xml:lang="DE">Verk&#xE4;ufe</word>
        <word xml:lang="EN">sales</word>
        <word xml:lang="ES">ventas</word>
        <word xml:lang="FR">ventes</word>
        <word xml:lang="IT">vendite</word>
        <word xml:lang="PT">vendas</word>
    </translate>
</dict>

XSLT File (funclang.xsl)

<?xml version='1.0'?>
<xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<!-- input parameters for testing -->
<xsl:param name="xlate_word">units</xsl:param>
<xsl:param name="xlate_lang">DE</xsl:param>

<xsl:template match="dict/translate">
    <xsl:for-each select="word[.=$xlate_word]">
        <p>
            Input word is: <xsl:value-of select="$xlate_word"/><br />
            Its language code is: <xsl:value-of select="@xml:lang"/>
        </p>
        <p>
            Translating to <xsl:value-of select="$xlate_lang"/>...<br />
            Translated value is: 
<xsl:value-of select="../*[lang($xlate_lang)]"/>
        </p>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

Formatted Output

Input word is: units
Its language code is: EN
Translating to DE...
Translated value is: Maßeinheiten

Processor Output

<?xml version="1.0" encoding="UTF-16"?><p>
            Input word is: units<br />
            Its language code is: EN</p><p>
            Translating to DE...<br />
            Translated value is: 
Maßeinheiten</p>