Set Operations
XML Path Language (XPath) supports the set operation |
.
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.
Expression | Refers to |
---|---|
|
A node set containing |
|
A node set containing |
|
A node set containing all |
|
The node set containing all |
The following example illustrates the effect of the union operator.
<?xml version="1.0"?>
<test>
<x a="1">
<x a="2" b="B">
<x>
<y>y31</y>
<y>y32</y>
</x>
</x>
</x>
</test>
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="https://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 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 |
The following example illustrates the effect of the operator precedence listed above.
<?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>
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="https://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>
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.
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>
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>
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>
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>
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>