Niek Tax
Niek Tax

Reputation: 841

Error returning attribute of distinct nodes

My xml file complies to the following DTD:

<!ELEMENT eprints (paper+)>
<!ELEMENT paper (eprintsid,userid,dir,datestamp,type,author+,title)>
<!ELEMENT eprintsid (#PCDATA)>
<!ELEMENT userid (#PCDATA)>
<!ELEMENT dir (#PCDATA)>
<!ELEMENT datestamp (#PCDATA)>
<!ELEMENT type (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT title (#PCDATA)>

<!ATTLIST author id CDATA #REQUIRED>

From this xml file I want to generate a list nodes of all distinct-values text nodes of author that match multiple id value, with the multiple id's as childnodes.

Therefore I tried using the following xquery:

let $doc := doc("eprints")
for $i in distinct-values($doc//author)
let $jn := $i/@id
where (count(distinct-values($jn)) > 1)
return <idByAuthor>{$jn}</idByAuthor>

Apparently XQuery does not allow me to traverse to the 'id' attribute node of $i, as I get the following error (from my xml database engine BaseX): 'context node required for '@id'; xs:untypedAtomic found.'.

Does anyone know why I can't reach the id attribute of $i?

Upvotes: 2

Views: 2013

Answers (2)

michael
michael

Reputation: 1577

you might want to have a look at the group by expression, introduced with XQuery 3.0 (see BaseX Doc).

Group by allows you to perform value based grouping, as such you could do something like in this Gist, Group By Example:

let $authors := 
<authors>
  <author id="a"><name>Foo</name>…whatever…</author>
  <author id="b"><name>Foo</name>…whatever…</author>
  <author id="a"><name>Foo</name>…whatever…</author>
  <author id="c"><name>Bar</name>…whatever…</author>
  <author id="d"><name>Bar</name>…whatever…</author>
  <author id="f"><name>FooBar</name>…whatever…</author>  
</authors> (: or use doc('eprints')//author :)
return
<distinct-names> {
  for $author in $authors//author
  group by $name := $author/name
  return
    if(count(distinct-values($author/@id)) > 1) then
      element {"author"}
              { 
                attribute {"name"} {$name},
                for $id in distinct-values($author/@id)
                return <id>{$id}</id>
              }
    else ()  
}</distinct-names>

I hope this helps, otherwise feel free to post a small snippet of your XML file.

Kind regards Michael

Upvotes: 2

Jens Erat
Jens Erat

Reputation: 38732

distinct-values(...) returns a set of atomic values (eg., numbers and strings), not XML nodes. You cannot do an axis step from these.

From this xml file I want to generate a list nodes of all distinct-values text nodes of author that match multiple id value, with the multiple id's as childnodes.

That's not the problem you want to solve, that's the way you're trying to solve it. I guess you want to query all authors which provided more than one paper (or what ever they're author of). If I guessed wrong please write exactly what your query should do.

Try following this sketch (not valid XQuery yet):

for all authors $a
where count of all papers with author $a
return <idByAuthor>{$a/@id}</idByAuthor>

If you need more help with this query, please post some example XML snippet to work with, if you've got some code for the query this code and the desired output.


Code for clearified question:

for $author in distinct-values($doc//author)
let $ids := $doc//author[data()=$author]/@id/data()
where count($ids) > 1
return
  <author name="{ $author }">
  {
    for $id in $ids
    return <id>{ $id }</id>
  }
  </author>

Upvotes: 4

Related Questions