XQuery 3.1/Build array of maps dynamically
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.
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
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.
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.
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"
}
]
}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
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.
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.
Written for BaseX 8.6. BaseX may have changed since: please check the current documentation.