Set Operations
XML Path Language (XPath) supports the set operation |.
Union (|) Operator
The |, or union, operator returns the union of its two operands, which must be node-sets. For example, //author | //publisher returns a node-set that combines all the //author nodes and all the //publisher nodes. Multiple union operators can be chained together to combine multiple node-sets. For example, //author | //publisher | //editor | //book-seller returns a node-set containing all //author, //publisher, //editor, and //book-seller elements. The union operator preserves document order and does not return duplicates.
Examples
| Expression | Refers to |
|---|---|
|
|
A node set containing |
|
|
A node set containing |
|
|
A node set containing all |
|
|
The node set containing all |
Example
The following example illustrates the effect of the union operator.
XML File (test.xml)
<?xml version="1.0"?> <test> <x a="1"> <x a="2" b="B"> <x> <y>y31</y> <y>y32</y> </x> </x> </x> </test>
XSLT File (test.xsl)
The following XSLT style sheet selects all the <x> elements whose a attribute is equal to 2, plus those <x> elements that have no attributes.
<?xml version='1.0'?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/> <!-- Suppress text nodes not covered in subsequent template rule. --> <xsl:template match="text()"/> <!-- Handles a generic element node. --> <xsl:template match="*"> <xsl:element name="{name()}"> <xsl:apply-templates select="*|@*" /> <xsl:if test="text()"> <xsl:value-of select="."/> </xsl:if> </xsl:element> </xsl:template> <!-- Handles a generic attribute node. --> <xsl:template match="@*"> <xsl:attribute name="{name()}"> <xsl:value-of select="."/> </xsl:attribute> </xsl:template> <xsl:template match="/test"> <xsl:apply-templates select="//x[@a=2] | //x[not(@*)]"/> </xsl:template> </xsl:stylesheet>
The transformation yields the following result:
<x a="2" b="B"> <x> <y>31</y> <y>y32</y> </x> </x> <x> <y>y31</y> <y>y32</y> </x>
Precedence
Precedence order (from highest precedence to lowest) between Boolean and comparison operators is shown in the following table.
| Precedence | Operators | Description |
|---|---|---|
|
1 |
|
Grouping |
|
2 |
|
Filters |
|
3 |
|
Path operations |
|
4 |
|
Comparisons |
|
5 |
|
Comparisons |
|
6 |
|
Union |
|
7 |
|
Boolean not |
|
8 |
|
Boolean and |
|
9 |
|
Boolean or |
Example
The following example illustrates the effect of the operator precedence listed above.
XML File (test.xml)
<?xml version="1.0"?> <test> <x a="1"> <x a="2" b="B"> <x> <y>y31</y> <y>y32</y> </x> </x> </x> <x a="1"> <x a="2"> <y>y21</y> <y>y22</y> </x> </x> <x a="1"> <y>y11</y> <y>y12</y> </x> <x> <y>y03</y> <y>y04</y> </x> </test>
Basic XSLT File (test.xsl)
We will use this basic XSLT file as a starting point for the series of illustrations that follow.
<?xml version='1.0'?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/> <!-- Suppress text nodes not covered in subsequent template rule. --> <xsl:template match="text()"/> <!-- Handles a generic element node. --> <xsl:template match="*"> <xsl:element name="{name()}"> <xsl:apply-templates select="*|@*" /> <xsl:if test="text()"> <xsl:value-of select="."/> </xsl:if> </xsl:element> </xsl:template> <!-- Handles a generic attribute node. --> <xsl:template match="@*"> <xsl:attribute name="{name()}"> <xsl:value-of select="."/> </xsl:attribute> </xsl:template> </xsl:stylesheet>
Case 0. Test run
You can add the following template-rule to the XSLT style sheet.
<xsl:template match="/test"> <xsl:apply-templates select="*|@*/> </xsl:template>
This will produce an XML document identical to the original one, without the <?xml version="1.0"?> processing instruction.
The following cases show different ways of writing this template rule. The point is to show the order in which the XPath operators bind to an element.
Case 1: () binds tighter than []
The following template rule selects the first <y> element in the document order, from all the <y> elements in the source document.
<xsl:template match="/test"> <xsl:apply-templates select="(//y)[1]"/> </xsl:template>
The result is as follows:
<y>y31</y>
Case 2: [] binds tighter than / or //
The following template rule selects all the <y> elements that are the first among their siblings.
<xsl:template match="/test"> <xsl:apply-templates select="//y[1]"/> </xsl:template>
The result is as follows:
<y>y31</y>
<y>y21</y>
<y>y11</y>
<y>y03</y>
Case 3: and, not
The following template rule selects all the <x> elements that have no <x> child elements, that have an <x> parent element, and that do not have any attributes.
<xsl:template match="/test"> <xsl:apply-templates select= "//x[./ancestor::*[name()='x'] and *[name()!='x'] and not(@*)]"/> </xsl:template>
The result is a single <x> element, listed below with its children:
<x> <y>y31</y> <y>y32</y> </x>
Case 4: or, and, not
The following template rule selects each <x> elements that is a child of an <x> element; or, that is not a parent of an <x> element and has no attributes.
<xsl:template match="/test"> <xsl:apply-templates select= "//x[./ancestor::*[name()='x'] or *[name()!='x'] and not(@*)]"/> </xsl:template>
The result is a node set containing the following <x> elements, listed below with its children:
<x a="2" b="B"> <x> <y>y31</y> <y>y32</y> </x> </x> <x> <y>y31</y> <y>y32</y> </x> <x a="2"> <y>y21</y> <y>y22</y> </x> <x> <y>y03</y> <y>y04</y> </x>
Case 5: and, or, not
The following template rule selects each <x> element that is a child of an <x> element but not a parent of an <x> element; or, that has no attributes.
<xsl:template match="/test"> <xsl:apply-templates select= "//x[./ancestor::*[name()='x'] and *[name()!='x'] or not(@*)]"/> </xsl:template>
The result is a node set containing the following <x> elements, listed below with its children:
<x> <y>y31</y> <y>y32</y> </x> <x a="2"> <y>y21</y> <y>y22</y> </x> <x> <y>y03</y> <y>y04</y> </x>
Build Date: