Jack
Jack

Reputation: 2605

How to find node with highest count?

Using XPath or a XQuery, how do I select the node with the most occurrences of another node?

For example how do I find the basket which has the most eggs?

<basket name="1">
        <egg></egg>
        <egg></egg>
</basket>
<basket name="2">
        <egg></egg>
</basket>
<basket name="3">
        <egg></egg>
        <egg></egg>
        <egg></egg>
        <egg></egg>
</basket>

Upvotes: 2

Views: 1865

Answers (3)

roman
roman

Reputation: 117400

<xml>
    <basket name="1">
        <egg></egg>
        <egg></egg>
    </basket>
    <basket name="2">
        <egg></egg>
    </basket>
    <basket name="3">
        <egg></egg>
        <egg></egg>
        <egg></egg>
        <egg></egg>
    </basket>
</xml>

you can try XPath like that

xml/basket[
    count(egg) > count(following-sibling::*/egg) and
    count(egg) > count(preceding-sibling::*/egg)
]

or if you want to count not only egg elements

xml/basket[
    count(child::*) > count(following-sibling::*/child::*) and
    count(child::*) > count(preceding-sibling::*/child::*)
]

Upvotes: 0

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243479

This is both an XPath 2.0 expression and an XQuery, that selects the wanted element(s):

/*/basket[egg[max(/*/basket/count(egg))]]

XSLT 2.0 - based verification:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/">
  <xsl:sequence select="/*/basket[egg[max(/*/basket/count(egg))]]"/>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the following XML document (your provided XML fragment, wrapped into a single top element to become a well-formed XML document):

<t>
    <basket name="1">
        <egg></egg>
        <egg></egg>
    </basket>
    <basket name="2">
        <egg></egg>
    </basket>
    <basket name="3">
        <egg></egg>
        <egg></egg>
        <egg></egg>
        <egg></egg>
    </basket>
</t>

The XPath expression is evaluated and the result of the evaluation is copied to the output:

<basket name="3">
        <egg/>
        <egg/>
        <egg/>
        <egg/>
    </basket>

Do note:

There is no such thing as "the node with the most occurances of another node".

In fact, depending on the actual XML document, there may be many elements that contain the same maximum number of other elements.

If you want to obtain just one such element, say the first in document order, then use:

/*/basket[egg[max(/*/basket/count(egg))]][1]

Upvotes: 1

Christian Gr&#252;n
Christian Gr&#252;n

Reputation: 6229

This is one solution (TIMTOWTDI):

let $nodes := <xml>
  <basket name="1">
          <egg></egg>
          <egg></egg>
  </basket>
  <basket name="2">
          <egg></egg>
  </basket>
  <basket name="3">
          <egg></egg>
          <egg></egg>
          <egg></egg>
          <egg></egg>
  </basket>
</xml>
let $max := max(for $c in $nodes//basket return count($c/egg))
return $nodes/basket[count(egg) = $max]

Upvotes: 3

Related Questions