11/*
2+ * Elemental
3+ * Copyright (C) 2024, Evolved Binary Ltd
4+ *
5+ * admin@evolvedbinary.com
6+ * https://www.evolvedbinary.com | https://www.elemental.xyz
7+ *
8+ * This library is free software; you can redistribute it and/or
9+ * modify it under the terms of the GNU Lesser General Public
10+ * License as published by the Free Software Foundation; version 2.1.
11+ *
12+ * This library is distributed in the hope that it will be useful,
13+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+ * Lesser General Public License for more details.
16+ *
17+ * You should have received a copy of the GNU Lesser General Public
18+ * License along with this library; if not, write to the Free Software
19+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20+ *
21+ * NOTE: Parts of this file contain code from 'The eXist-db Authors'.
22+ * The original license header is included below.
23+ *
24+ * =====================================================================
25+ *
226 * eXist-db Open Source Native XML Database
327 * Copyright (C) 2001 The eXist-db Authors
428 *
2751import org .exist .xquery .util .ExpressionDumper ;
2852import org .exist .xquery .value .*;
2953
54+ import javax .annotation .Nullable ;
55+
3056/**
3157 * Implements the XQuery 3.1 lookup operator on maps and arrays.
3258 *
3359 * @author Wolfgang
3460 */
3561public class Lookup extends AbstractExpression {
3662
37- private Expression contextExpression ;
38- private Sequence keys = null ;
39- private Expression keyExpression = null ;
63+ private final Expression contextExpression ;
64+ private @ Nullable Sequence keys = null ;
65+ private @ Nullable Expression keyExpression = null ;
4066
41- public Lookup (XQueryContext context , Expression ctxExpr ) {
67+ public Lookup (final XQueryContext context , final Expression contextExpression ) {
4268 super (context );
43- this .contextExpression = ctxExpr ;
69+ this .contextExpression = contextExpression ;
4470 }
4571
46- public Lookup (XQueryContext context , Expression ctxExpr , String keyString ) {
47- this (context , ctxExpr );
48- this .keys = new StringValue (ctxExpr , keyString );
72+ public Lookup (final XQueryContext context , final Expression contextExpression , final String keyString ) {
73+ this (context , contextExpression );
74+ this .keys = new StringValue (contextExpression , keyString );
4975 }
5076
51- public Lookup (XQueryContext context , Expression ctxExpr , int position ) {
52- this (context , ctxExpr );
53- this .keys = new IntegerValue (ctxExpr , position );
77+ public Lookup (final XQueryContext context , final Expression contextExpression , final int position ) {
78+ this (context , contextExpression );
79+ this .keys = new IntegerValue (contextExpression , position );
5480 }
5581
56- public Lookup (XQueryContext context , Expression ctxExpr , Expression keyExpression ) {
57- this (context , ctxExpr );
82+ public Lookup (final XQueryContext context , final Expression contextExpression , @ Nullable final Expression keyExpression ) {
83+ this (context , contextExpression );
5884 this .keyExpression = keyExpression ;
5985 }
6086
6187 @ Override
62- public void analyze (AnalyzeContextInfo contextInfo ) throws XPathException {
88+ public void analyze (final AnalyzeContextInfo contextInfo ) throws XPathException {
6389 final AnalyzeContextInfo contextCopy = new AnalyzeContextInfo (contextInfo );
6490 if (contextExpression != null ) {
6591 contextExpression .analyze (contextCopy );
@@ -70,16 +96,18 @@ public void analyze(AnalyzeContextInfo contextInfo) throws XPathException {
7096 }
7197
7298 @ Override
73- public Sequence eval (Sequence contextSequence , Item contextItem ) throws XPathException {
99+ public Sequence eval (Sequence contextSequence , final Item contextItem ) throws XPathException {
74100 if (contextItem != null ) {
75101 contextSequence = contextItem .toSequence ();
76102 }
77- Sequence leftSeq ;
103+
104+ final Sequence leftSeq ;
78105 if (contextExpression == null && contextSequence == null ) {
79- throw new XPathException (this , ErrorCodes .XPDY0002 ,
80- "Lookup has nothing to select, the context item is absent" );
106+ throw new XPathException (this , ErrorCodes .XPDY0002 , "Lookup has nothing to select, the context item is absent" );
107+
81108 } else if (contextExpression == null ) {
82109 leftSeq = contextSequence ;
110+
83111 } else {
84112 leftSeq = contextExpression .eval (contextSequence , null );
85113 }
@@ -90,39 +118,44 @@ public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathExc
90118 return Sequence .EMPTY_SEQUENCE ;
91119 }
92120
93-
94121 if (!(Type .subTypeOf (contextType , Type .MAP_ITEM ) || Type .subTypeOf (contextType , Type .ARRAY_ITEM ))) {
95- throw new XPathException (this , ErrorCodes .XPTY0004 ,
96- "expression to the left of a lookup operator needs to be a sequence of maps or arrays" );
122+ throw new XPathException (this , ErrorCodes .XPTY0004 , "expression to the left of a lookup operator needs to be a sequence of maps or arrays" );
97123 }
124+
98125 if (keyExpression != null ) {
99126 keys = keyExpression .eval (contextSequence , null );
100127 if (keys .isEmpty ()) {
101128 return Sequence .EMPTY_SEQUENCE ;
102129 }
103130 }
131+
104132 try {
105133 final ValueSequence result = new ValueSequence ();
106- for (SequenceIterator i = leftSeq .iterate (); i .hasNext (); ) {
134+ for (final SequenceIterator i = leftSeq .iterate (); i .hasNext (); ) {
107135 final LookupSupport item = (LookupSupport ) i .nextItem ();
136+
108137 if (keys != null ) {
109- for (SequenceIterator j = keys .iterate (); j .hasNext (); ) {
138+ for (final SequenceIterator j = keys .iterate (); j .hasNext (); ) {
110139 final AtomicValue key = j .nextItem ().atomize ();
111- Sequence value = item .get (key );
140+ final Sequence value = item .get (key );
112141 if (value != null ) {
113142 result .addAll (value );
114143 }
115144 }
116- } else if (item instanceof ArrayType ) {
145+
146+ } else if (item instanceof ArrayType ) {
117147 result .addAll (item .keys ());
118- } else if (item instanceof AbstractMapType ) {
119- for (final IEntry <AtomicValue , Sequence > entry : ((AbstractMapType )item )) {
148+
149+ } else if (item instanceof AbstractMapType ) {
150+ for (final IEntry <AtomicValue , Sequence > entry : ((AbstractMapType )item )) {
120151 result .addAll (entry .value ());
121152 }
122153 }
123154 }
155+
124156 return result ;
125- } catch (XPathException e ) {
157+
158+ } catch (final XPathException e ) {
126159 e .setLocation (getLine (), getColumn (), getSource ());
127160 throw e ;
128161 }
@@ -139,29 +172,35 @@ public Cardinality getCardinality() {
139172 }
140173
141174 @ Override
142- public void dump (ExpressionDumper dumper ) {
175+ public void dump (final ExpressionDumper dumper ) {
143176 if (contextExpression != null ) {
144177 contextExpression .dump (dumper );
145178 }
179+
146180 dumper .display ("?" );
181+
147182 if (keyExpression == null && keys != null && keys .getItemCount () > 0 ) {
148183 try {
149184 dumper .display (keys .itemAt (0 ).getStringValue ());
150- } catch (XPathException e ) {
185+ } catch (final XPathException e ) {
151186 // impossible
152187 }
188+
153189 } else if (keyExpression != null ) {
154190 keyExpression .dump (dumper );
155191 }
156192 }
157193
158194 @ Override
159- public void resetState (boolean postOptimization ) {
195+ public void resetState (final boolean postOptimization ) {
160196 super .resetState (postOptimization );
197+
161198 if (contextExpression != null ) {
162199 contextExpression .resetState (postOptimization );
163200 }
201+
164202 if (keyExpression != null ) {
203+ keys = null ;
165204 keyExpression .resetState (postOptimization );
166205 }
167206 }
0 commit comments