Hi all,
on the way to writing a small DSL I stumbled upon the following BaseX
7.6 issue.
I'm not able to explain to myself why the first two expressions of the
following xquery module return correctly whereas the last yields
NullPointerException (as shown in the appended stacktrace).
What I'm mtrying to do is to wrap up some modification code into
userfriendly function calls that can be used in mini xquery scripts to
formalize xml workflow.
Thank you for any help,
Marco.
declare variable $globals := map {
'change' := local:change#1,
'generate' := local:gen#0
};
declare function local:gen(){
<b/>
};
declare function local:change($doc){
copy $newdoc := $doc
modify(
insert node <a/> as last into $newdoc
)
return $newdoc
};
(
xquery:eval("copy $newdoc := <b/>
modify(
insert node <a/> as last into $newdoc
)
return $newdoc",$globals),
xquery:eval("$generate()", $globals),
xquery:eval("$change($doc)", map:new( ($globals, map { "doc" := <b/>})))
)
The stacktrace and query plan:
Error:
Improper use? Potential bug? Your feedback is welcome:
Contact: basex-talk(a)mailman.uni-konstanz.de
Version: BaseX 7.6
Java: Oracle Corporation, 1.7.0_15
OS: Linux, i386
Stack Trace:
java.lang.NullPointerException
org.basex.query.up.expr.Transform.value(Transform.java:68)
org.basex.query.QueryContext.value(QueryContext.java:296)
org.basex.query.func.UserFunc.value(UserFunc.java:175)
org.basex.query.QueryContext.value(QueryContext.java:296)
org.basex.query.func.BaseFuncCall.value(BaseFuncCall.java:68)
org.basex.query.QueryContext.value(QueryContext.java:296)
org.basex.query.value.item.FuncItem.invValue(FuncItem.java:104)
org.basex.query.func.DynamicFunc.value(DynamicFunc.java:56)
org.basex.query.QueryContext.value(QueryContext.java:296)
org.basex.query.QueryContext.value(QueryContext.java:254)
org.basex.query.func.FNXQuery.eval(FNXQuery.java:95)
org.basex.query.func.FNXQuery.eval(FNXQuery.java:71)
org.basex.query.func.FNXQuery.iter(FNXQuery.java:37)
org.basex.query.QueryContext.iter(QueryContext.java:285)
org.basex.query.expr.List$1.next(List.java:100)
org.basex.query.QueryContext.execute(QueryContext.java:524)
org.basex.query.QueryProcessor.execute(QueryProcessor.java:96)
org.basex.core.cmd.AQuery.query(AQuery.java:77)
org.basex.core.cmd.XQuery.run(XQuery.java:22)
org.basex.core.Command.run(Command.java:342)
org.basex.core.Command.exec(Command.java:321)
org.basex.core.Command.execute(Command.java:78)
org.basex.gui.GUI.exec(GUI.java:397)
org.basex.gui.GUI$7.run(GUI.java:349)
Compiling:
- pre-evaluating map { "change":=function($1) as item()* {
local:change(($1)) }, "generate":=function() as item()* { local:gen(()) } }
Optimized Query:
declare function local:change($doc) { copy $newdoc as node() := $doc
modify insert node element a { () } into $newdoc return $newdoc };
declare function local:gen() { element b { () } };
(xquery:eval("copy $newdoc := $generate()
modify(
insert node <a/> as last into $newdoc
)
return $newdoc", map{ "change":=function($1) as item()*
{ local:change(($1)) }, "generate":=function() as item()* {
local:gen(()) } }), xquery:eval("$generate()", map{
"change":=function($1) as item()* { local:change(($1)) },
"generate":=function() as item()* { local:gen(()) } }),
xquery:eval("$change($doc)", map:new((map{ "change":=function($1) as
item()* { local:change(($1)) }, "generate":=function() as item()* {
local:gen(()) } }, map { "doc":=element b { () } }))))
Query plan:
<QueryPlan>
<UserFuncs>
<UserFunc name="local:change" arg0="doc">
<Transform>
<Let var="$newdoc as node()">
<VarRef>
<Var name="$doc" id="2"/>
</VarRef>
</Let>
<Insert>
<VarRef>
<Var name="$newdoc as node()" id="3"/>
</VarRef>
<CElem>
<QNm value="a" type="xs:QName"/>
</CElem>
</Insert>
<VarRef>
<Var name="$newdoc as node()" id="3"/>
</VarRef>
</Transform>
</UserFunc>
<UserFunc name="local:gen">
<CElem>
<QNm value="b" type="xs:QName"/>
</CElem>
</UserFunc>
</UserFuncs>
<VarStack>
<Var name="$globals" id="0"/>
</VarStack>
<List>
<FNXQuery name="eval(string[,bindings])">
<Str value="copy $newdoc := $generate()

modify(
 insert node <a/> as last into
$newdoc 
 )
 return $newdoc" type="xs:string"/>
<Map size="2">
<Str value="change" type="xs:string"/>
<FuncItem type="function(item()*) as item()*">
<Var name="$1" id="1"/>
<BaseFuncCall name="local:change(($1))">
<VarRef>
<Var name="$1" id="1"/>
</VarRef>
</BaseFuncCall>
</FuncItem>
<Str value="generate" type="xs:string"/>
<FuncItem type="function() as item()*">
<BaseFuncCall name="local:gen(())"/>
</FuncItem>
</Map>
</FNXQuery>
<FNXQuery name="eval(string[,bindings])">
<Str value="$generate()" type="xs:string"/>
<Map size="2">
<Str value="change" type="xs:string"/>
<FuncItem type="function(item()*) as item()*">
<Var name="$1" id="1"/>
<BaseFuncCall name="local:change(($1))">
<VarRef>
<Var name="$1" id="1"/>
</VarRef>
</BaseFuncCall>
</FuncItem>
<Str value="generate" type="xs:string"/>
<FuncItem type="function() as item()*">
<BaseFuncCall name="local:gen(())"/>
</FuncItem>
</Map>
</FNXQuery>
<FNXQuery name="eval(string[,bindings])">
<Str value="$change($doc)" type="xs:string"/>
<FNMap name="new([maps[,coll]])">
<List>
<Map size="2">
<Str value="change" type="xs:string"/>
<FuncItem type="function(item()*) as item()*">
<Var name="$1" id="1"/>
<BaseFuncCall name="local:change(($1))">
<VarRef>
<Var name="$1" id="1"/>
</VarRef>
</BaseFuncCall>
</FuncItem>
<Str value="generate" type="xs:string"/>
<FuncItem type="function() as item()*">
<BaseFuncCall name="local:gen(())"/>
</FuncItem>
</Map>
<LitMap>
<Str value="doc" type="xs:string"/>
<CElem>
<QNm value="b" type="xs:QName"/>
</CElem>
</LitMap>
</List>
</FNMap>
</FNXQuery>
</List>
</QueryPlan>