3

my xml data:

<a>
   <book>
        <pub>John</pub>
   </book>
   <book>
        <pub>John</pub>
    </book>
    <book>
         <pub>Mary</pub>
    </book>
</a>

So i want to count number for each and display them

Expected output:

 <result>
         <pub>John</pub>
         <total>2</total>
 </result>
 <result>
         <pub>Mary</pub>
         <total>1</total>
  </result>

But my output:

 <result>
         <pub>John</pub>
         <total>1</total>
 </result>
<result>
         <pub>John</pub>
         <total>1</total>
 </result>
 <result>
         <pub>Mary</pub>
         <total>1</total>
  </result>

code i using :

for $b in /a/book
let $count := count($b/pub)
for $pub in $b/pub
return
     <result> {$pub} <total>{$count}</total></result>

it keep looping the same data but not group it . even i use distinct-values it's still same. what error in my code?

2 Answers 2

2

If using an XQuery 3.0 capable XQuery processor, you can also take advantage of the group by flwor statement:

for $book in /a/book
let $publisher := $book/pub
group by $publisher
return
  <result>
    <pub>{ $publisher }</pub>
    <count>{ count($book) }</count>
   </result>
Sign up to request clarification or add additional context in comments.

Comments

1

Grouping works using distinct-values. You can count all the books or pubs and filter only the ones that match the current iteration.

This:

let $b := /a/book/pub
  for $pub in distinct-values($b)
      let $count := count($b[. eq $pub])
      return <result>
                <pub>{$pub}</pub> 
                <total>{$count}</total>
             </result>

will produce:

<result>
   <pub>John</pub>
   <total>2</total>
</result>
<result>
   <pub>Mary</pub>
   <total>1</total>
</result>

4 Comments

want to understand. what is this code for let $count := count($b[. eq $pub]) why got . inside?
$pub is the current node (/a/book/pub) in the context of the for loop. $b is a set containing all nodes (total of 3): /a/book/pub[1], /a/book/pub[2] and /a/book/pub[3]. Basically in each iteration of the loop, you compare the current node $pub with all three nodes, and select only the ones which have the same string value as $pub. The . inside the predicate "[...]" represents the node itself (predicates in XPath are contextual). Since I'm relying on the string value. You could also replace the . for node() or text().
If you remove the predicate [. eq $pub] you should get the total value always (3), since $b doesn't change in the loop. If you use count($pub) you will always get 1, because there is only one pub per iteration of the loop.
so i can change to count($b[text() = $pub/text()])?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.