The distinct-values
function selects distinct atomic values from a sequence. For example, the function call:
distinct-values(doc("catalog.xml")//product/@dept)
returns all the distinct values of the dept
attribute, namely ("WMN", "ACC", "MEN")
. This function determines whether two values are distinct based on their value equality using the eq
operator.
It is also common to select a distinct set of combinations of values. For example, you might want to select all the distinct department/product number combinations from the product catalog. You cannot use the distinct-values
function directly for this, because it accepts only one sequence of atomic values, not multiple sequences of multiple values. Instead, you could use the expression shown in Example 6-12.
Example 6-12. Distinctness on a combination of values
Query let $prods := doc("catalog.xml")//product for $d in distinct-values($prods/@dept), $n in distinct-values($prods[@dept = $d]/number) return <result dept="{$d}" number="{$n}"/> Results <result dept="WMN" number="557"/> <result dept="ACC" number="563"/> <result dept="ACC" number="443"/> <result dept="MEN" number="784"/>
For each distinct department, assigned to $d
, it generates a list of distinct product numbers within that department using the predicate [@dept = $d]
. It then returns the resulting combination of values as a result
element. The order in which the values are returned is implementation-dependent, so it can be unpredictable.
Additional data items can be added by adding for
clauses with the appropriate predicates.
distinct-deep
Suppose you want to find distinct elements based on all of their children and attributes. You could use an expression similar to the one shown in Example 6-12, but it could get complicated if there are many elements and attributes to compare. Also, you would be required to know the names of all the attributes and child elements in advance. A more generic function, shown here, can be used to select distinct nodes based on all of their contents:
declare namespace functx = "http://www.functx.com"; declare function functx:distinct-deep ($nodes as node()*) as node( )* { for $x in (1 to count($nodes)) let $node := $nodes[$x] let $restOfNodes := subsequence($nodes, $x + 1) return if (some $otherNode in $restOfNodes satisfies (deep-equal($otherNode, $node))) then ( ) else $node };
For each node in a sequence, the function determines whether the node has the same contents as any nodes that occur later in the sequence. Any nodes that have later matches are eliminated. The function makes use of the deep-equal
function, which compares two elements based on their attributes and children. It is also a good example of the usefulness of quantified expressions.
For example, suppose your product catalog is very large, and you suspect that there are duplicate entries that need to be eliminated from the query results. The function call:
functx:distinct-deep(doc("catalog.xml")//product)
returns only distinct product
elements, based on all of their content and attributes.
18.216.151.164