XQuery 3.1/Build array of maps dynamically

Tuesday, 12 December 2017 · 7 messages
HE
Hondros, Constantine (ELS-AMS)12 Dec 2017 13:16 #
Hello all, I want to dynamically build a map where the value is an array of maps. I am having a problem with the syntax. (My use-case is to deliver this as JSON for simple ingestion to Spark, by the way). Here's my test code, which translates cleanly into JSON:
declare option output:method 'json';
  map {
    "authors": [ map{"fn":"John", "ln":"Smith"}, map{"fn":"Jane", "ln":"Doe"} ]
}
However, when I try to build the same map dynamically, I get the error "Value has more than one item". I guess this is because my for loop is returning a sequence, but I can't figure out the syntax to get it working. Any ideas?
declare option output:method 'json';
map {
    "authors": [
      (for $b in $authors return    (: just assume $authors is populated ...:)
        map{"fn":$b/*:given-name/text(), "ln":$b/*:surname/text()})
    ]
}
TIA! ________________________________ Elsevier B.V. Registered Office: Radarweg 29, 1043 NX Amsterdam, The Netherlands, Registration No. 33156677, Registered in The Netherlands.
CG
Christian Grün12 Dec 2017 13:20 #
Hi Constantine,
Quoted text · Hondros, Constantine (ELS-AMS) · 1 line
> (: just assume $authors is populated ...:)
Could you provide us with a little self-contained example? Because there are all kinds of populations out there. TIA as well, Christian
HE
Hondros, Constantine (ELS-AMS)12 Dec 2017 13:30 #
Hi Christian, I was already kicking myself for rushing and not providing a SCE! Please see the code below, and thanks.
declare option output:method 'json';

declare variable $authors := <authors>

    <author>

        <given-name>Robert A</given-name>

        <surname>Sanders</surname>

    </author>

    <author>

        <given-name>Emily</given-name>

        <surname>Chapel</surname>

    </author>

</authors>;

map {
"authors": [ (for $b in $authors/author return map{"fn":$b/*:given-name/text(), "ln":$b/*:surname/text()}) ] }
Quoted text · Christian Grün · 13 lines
-----Original Message----- From: Christian Grün [mailto:christian.gruen at gmail.com] Sent: 12 December 2017 13:20 To: Hondros, Constantine (ELS-AMS) Cc: basex-talk at mailman.uni-konstanz.de Subject: Re: [basex-talk] XQuery 3.1/Build array of maps dynamically *** External email: use caution *** Hi Constantine, > (: just assume $authors is populated ...:) Could you provide us with a little self-contained example? Because there are all kinds of populations out there. TIA as well, Christian Elsevier B.V. Registered Office: Radarweg 29, 1043 NX Amsterdam, The Netherlands, Registration No. 33156677, Registered in The Netherlands.
CG
Christian Grün12 Dec 2017 13:32 #
Thanks. Your query does not yield “Value has more than one item”, at least with the latest snapshot of BaseX. But maybe you are expecting another result?
Quoted text · Constantine (ELS-AMS) · 90 lines
On Tue, Dec 12, 2017 at 1:30 PM, Hondros, Constantine (ELS-AMS) <C.Hondros at elsevier.com> wrote: > Hi Christian, > > I was already kicking myself for rushing and not providing a SCE! Please see > the code below, and thanks. > > > > declare option output:method 'json'; > > > > declare variable $authors := <authors> > > <author> > > <given-name>Robert A</given-name> > > <surname>Sanders</surname> > > </author> > > <author> > > <given-name>Emily</given-name> > > <surname>Chapel</surname> > > </author> > > </authors>; > > > > map { > > "authors": [ > > (for $b in $authors/author return > > map{"fn":$b/*:given-name/text(), "ln":$b/*:surname/text()}) > > ] > > } > > > > > > -----Original Message----- > From: Christian Grün [mailto:christian.gruen at gmail.com] > Sent: 12 December 2017 13:20 > To: Hondros, Constantine (ELS-AMS) > Cc: basex-talk at mailman.uni-konstanz.de > Subject: Re: [basex-talk] XQuery 3.1/Build array of maps dynamically > > > > *** External email: use caution *** > > > > > > > > Hi Constantine, > > > >> (: just assume $authors is populated ...:) > > > > Could you provide us with a little self-contained example? Because there are > all kinds of populations out there. > > > > TIA as well, > > Christian > > > ________________________________ > > Elsevier B.V. Registered Office: Radarweg 29, 1043 NX Amsterdam, The > Netherlands, Registration No. 33156677, Registered in The Netherlands.
MH
Martin Honnenin reply to Hondros, Constantine (ELS-AMS), 12 Dec 2017, 13:3012 Dec 2017 13:38 #
Quoted text · Constantine (ELS-AMS) · 37 lines
On 12.12.2017 13:30, Hondros, Constantine (ELS-AMS) wrote: > I was already kicking myself for rushing and not providing a SCE! Please > see the code below, and thanks. > > declare option output:method 'json'; > > declare variable $authors := <authors> > > <author> > > <given-name>Robert A</given-name> > > <surname>Sanders</surname> > > </author> > > <author> > > <given-name>Emily</given-name> > > <surname>Chapel</surname> > > </author> > > </authors>; > > map { > > "authors": [ > > (for $b in $authors/author return > > map{"fn":$b/*:given-name/text(), "ln":$b/*:surname/text()}) > > ] > > }
I think to get the map structure from your earlier sample you want
declare option output:method 'json';

declare variable $authors := <authors>

     <author>

         <given-name>Robert A</given-name>

         <surname>Sanders</surname>

     </author>

     <author>

         <given-name>Emily</given-name>

         <surname>Chapel</surname>

     </author>

</authors>;

map {

     "authors": array{$authors/author!map{"fn" : data(given-name), "ln"
: data(surname)}}
} Result is
{
   "authors": [
     {
       "ln": "Sanders",
       "fn": "Robert A"
     },
     {
       "ln": "Chapel",
       "fn": "Emily"
     }
   ]
}
CG
Christian Grünin reply to Christian Grün, 12 Dec 2017, 13:3212 Dec 2017 13:40 #
This time I was too quick, sorry (I ignored the query prolog of your query). This is the fixed version:
  declare namespace output = 'http://www.w3.org/2010/xslt-xquery-serialization';
  declare option output:method 'json';

  declare variable $authors :=
    <authors>
      <author>
        <given-name>Robert A</given-name>
        <surname>Sanders</surname>
      </author>
      <author>
        <given-name>Emily</given-name>
        <surname>Chapel</surname>
      </author>
    </authors>;

  map {
    "authors": array {
      for $b in $authors/author
      return map {
        "fn": $b/*:given-name/text(),
        "ln": $b/*:surname/text()
      }
    }
  }
Check out [1] to learn about the subtle difference betwen [] and array {}. Best, Christian [1] http://docs.basex.org/wiki/XQuery_3.1#Arrays
Quoted text · Christian Grün · 97 lines
On Tue, Dec 12, 2017 at 1:32 PM, Christian Grün <christian.gruen at gmail.com> wrote: > Thanks. Your query does not yield “Value has more than one item”, at > least with the latest snapshot of BaseX. But maybe you are expecting > another result? > > > On Tue, Dec 12, 2017 at 1:30 PM, Hondros, Constantine (ELS-AMS) > <C.Hondros at elsevier.com> wrote: >> Hi Christian, >> >> I was already kicking myself for rushing and not providing a SCE! Please see >> the code below, and thanks. >> >> >> >> declare option output:method 'json'; >> >> >> >> declare variable $authors := <authors> >> >> <author> >> >> <given-name>Robert A</given-name> >> >> <surname>Sanders</surname> >> >> </author> >> >> <author> >> >> <given-name>Emily</given-name> >> >> <surname>Chapel</surname> >> >> </author> >> >> </authors>; >> >> >> >> map { >> >> "authors": [ >> >> (for $b in $authors/author return >> >> map{"fn":$b/*:given-name/text(), "ln":$b/*:surname/text()}) >> >> ] >> >> } >> >> >> >> >> >> -----Original Message----- >> From: Christian Grün [mailto:christian.gruen at gmail.com] >> Sent: 12 December 2017 13:20 >> To: Hondros, Constantine (ELS-AMS) >> Cc: basex-talk at mailman.uni-konstanz.de >> Subject: Re: [basex-talk] XQuery 3.1/Build array of maps dynamically >> >> >> >> *** External email: use caution *** >> >> >> >> >> >> >> >> Hi Constantine, >> >> >> >>> (: just assume $authors is populated ...:) >> >> >> >> Could you provide us with a little self-contained example? Because there are >> all kinds of populations out there. >> >> >> >> TIA as well, >> >> Christian >> >> >> ________________________________ >> >> Elsevier B.V. Registered Office: Radarweg 29, 1043 NX Amsterdam, The >> Netherlands, Registration No. 33156677, Registered in The Netherlands.
HE
Hondros, Constantine (ELS-AMS)12 Dec 2017 14:08 #
Ah, fantastic. Thank you Christian (and Martin). Yes, I was using an incorrect constructor for Arrays in this instance. Many thanks, Constantine
Quoted text · Christian Grün · 132 lines
-----Original Message----- From: Christian Grün [mailto:christian.gruen at gmail.com] Sent: 12 December 2017 13:41 To: Hondros, Constantine (ELS-AMS) Cc: basex-talk at mailman.uni-konstanz.de Subject: Re: [basex-talk] XQuery 3.1/Build array of maps dynamically *** External email: use caution *** This time I was too quick, sorry (I ignored the query prolog of your query). This is the fixed version: declare namespace output = 'http://www.w3.org/2010/xslt-xquery-serialization'; declare option output:method 'json'; declare variable $authors := <authors> <author> <given-name>Robert A</given-name> <surname>Sanders</surname> </author> <author> <given-name>Emily</given-name> <surname>Chapel</surname> </author> </authors>; map { "authors": array { for $b in $authors/author return map { "fn": $b/*:given-name/text(), "ln": $b/*:surname/text() } } } Check out [1] to learn about the subtle difference betwen [] and array {}. Best, Christian [1] http://docs.basex.org/wiki/XQuery_3.1#Arrays On Tue, Dec 12, 2017 at 1:32 PM, Christian Grün <christian.gruen at gmail.com> wrote: > Thanks. Your query does not yield “Value has more than one item”, at > least with the latest snapshot of BaseX. But maybe you are expecting > another result? > > > On Tue, Dec 12, 2017 at 1:30 PM, Hondros, Constantine (ELS-AMS) > <C.Hondros at elsevier.com> wrote: >> Hi Christian, >> >> I was already kicking myself for rushing and not providing a SCE! >> Please see the code below, and thanks. >> >> >> >> declare option output:method 'json'; >> >> >> >> declare variable $authors := <authors> >> >> <author> >> >> <given-name>Robert A</given-name> >> >> <surname>Sanders</surname> >> >> </author> >> >> <author> >> >> <given-name>Emily</given-name> >> >> <surname>Chapel</surname> >> >> </author> >> >> </authors>; >> >> >> >> map { >> >> "authors": [ >> >> (for $b in $authors/author return >> >> map{"fn":$b/*:given-name/text(), "ln":$b/*:surname/text()}) >> >> ] >> >> } >> >> >> >> >> >> -----Original Message----- >> From: Christian Grün [mailto:christian.gruen at gmail.com] >> Sent: 12 December 2017 13:20 >> To: Hondros, Constantine (ELS-AMS) >> Cc: basex-talk at mailman.uni-konstanz.de >> Subject: Re: [basex-talk] XQuery 3.1/Build array of maps dynamically >> >> >> >> *** External email: use caution *** >> >> >> >> >> >> >> >> Hi Constantine, >> >> >> >>> (: just assume $authors is populated ...:) >> >> >> >> Could you provide us with a little self-contained example? Because >> there are all kinds of populations out there. >> >> >> >> TIA as well, >> >> Christian >> >> >> ________________________________ >> >> Elsevier B.V. Registered Office: Radarweg 29, 1043 NX Amsterdam, The >> Netherlands, Registration No. 33156677, Registered in The Netherlands. Elsevier B.V. Registered Office: Radarweg 29, 1043 NX Amsterdam, The Netherlands, Registration No. 33156677, Registered in The Netherlands.

⚡Generated with XQuery