• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

eXist-db / exist / 40385135706

26 Oct 2026 07:15PM UTC coverage: 58.168% (+0.03%) from 58.138%
40385135706

push

github

web-flow
Merge pull request #6927 from wylovan/bugfix/2097-path-step-mutates-variable

[bugfix] Leave a variable unchanged when a path step is applied to it

32488 of 61728 branches covered (52.63%)

Branch coverage included in aggregate %.

85545 of 141188 relevant lines covered (60.59%)

2.73 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

17.5
/exist-core/src/main/java/org/exist/xquery/value/ArrayListValueSequence.java
1
/*
2
 * Copyright (C) 2014, Evolved Binary Ltd
3
 *
4
 * This file was originally ported from FusionDB to eXist-db by
5
 * Evolved Binary, for the benefit of the eXist-db Open Source community.
6
 * Only the ported code as it appears in this file, at the time that
7
 * it was contributed to eXist-db, was re-licensed under The GNU
8
 * Lesser General Public License v2.1 only for use in eXist-db.
9
 *
10
 * This license grant applies only to a snapshot of the code as it
11
 * appeared when ported, it does not offer or infer any rights to either
12
 * updates of this source code or access to the original source code.
13
 *
14
 * The GNU Lesser General Public License v2.1 only license follows.
15
 *
16
 * ---------------------------------------------------------------------
17
 *
18
 * Copyright (C) 2014, Evolved Binary Ltd
19
 *
20
 * This library is free software; you can redistribute it and/or
21
 * modify it under the terms of the GNU Lesser General Public
22
 * License as published by the Free Software Foundation; version 2.1.
23
 *
24
 * This library is distributed in the hope that it will be useful,
25
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
27
 * Lesser General Public License for more details.
28
 *
29
 * You should have received a copy of the GNU Lesser General Public
30
 * License along with this library; if not, write to the Free Software
31
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
32
 */
33
package org.exist.xquery.value;
34

35
import org.apache.logging.log4j.LogManager;
36
import org.apache.logging.log4j.Logger;
37
import org.exist.dom.memtree.DocumentImpl;
38
import org.exist.dom.memtree.NodeImpl;
39
import org.exist.dom.persistent.NewArrayNodeSet;
40
import org.exist.dom.persistent.NodeProxy;
41
import org.exist.dom.persistent.NodeSet;
42
import org.exist.numbering.NodeId;
43
import org.exist.xquery.ErrorCodes;
44
import org.exist.xquery.Expression;
45
import org.exist.xquery.NodeTest;
46
import org.exist.xquery.XPathException;
47
import org.exist.xquery.XQueryContext;
48
import org.w3c.dom.Document;
49
import org.w3c.dom.Node;
50

51
import javax.annotation.Nullable;
52
import java.util.*;
53

54
/**
55
 * Alternative to {@link ValueSequence}, this version
56
 * is much faster, but it does not support sorting!
57
 *
58
 * @author <a href="mailto:adam@evolvedbinary.com">Adam Retter</a>
59
 */
60
public class ArrayListValueSequence extends AbstractSequence implements MemoryNodeSet {
61

62
    private final static Logger LOG = LogManager.getLogger(ArrayListValueSequence.class);
4 ✔
63

64
    private final List<Item> values;
65

66
    // used to keep track of the type of added items.
67
    // will be Type.ANY_TYPE if the type is unknown
68
    // and Type.ITEM if there are items of mixed type.
69
    private int itemType = Type.ANY_TYPE;
6 ✔
70

71
    private int state = 0;
6 ✔
72

73
    public ArrayListValueSequence() {
2 ✔
74
        this.isEmpty = true;
3 ✔
75
        this.hasOne = false;
3 ✔
76
        this.values = new ArrayList<>();
5 ✔
77
    }
1 ✔
78

79
    public ArrayListValueSequence(final int initialSize) {
2 ✔
80
        this.isEmpty = true;
3 ✔
81
        this.hasOne = false;
3 ✔
82
        this.values = new ArrayList<>(initialSize);
6 ✔
83
    }
1 ✔
84

85
    public ArrayListValueSequence(final Sequence otherSequence) throws XPathException {
×
86
        this.isEmpty = true;
×
87
        this.hasOne = false;
×
88
        this.values = new ArrayList<>(otherSequence.getItemCount());
×
89
        addAll(otherSequence);
×
90
    }
×
91

92
    public ArrayListValueSequence(final Item... items) {
×
93
        this.isEmpty = true;
×
94
        this.hasOne = false;
×
95
        this.values = new ArrayList<>(items.length);
×
96
        addAll(Arrays.asList(items), null);
×
97
    }
×
98

99
    public void clear() {
100
        if (!isEmpty) {
×
101
            setHasChanged();
×
102
        }
103

104
        values.clear();
×
105
        this.itemType = Type.ANY_TYPE;
×
106
        this.isEmpty = true;
×
107
        this.hasOne = false;
×
108
    }
×
109

110
    @Override
111
    public boolean isEmpty() {
112
        return isEmpty;
3 ✔
113
    }
114

115
    @Override
116
    public boolean hasOne() {
117
        return hasOne;
3 ✔
118
    }
119

120
    @Override
121
    public void add(final Item item) {
122
        if (hasOne) {
3 ✔
123
            hasOne = false;
3 ✔
124
        }
125
        if (isEmpty) {
3 ✔
126
            isEmpty = false;
3 ✔
127
            hasOne = true;
3 ✔
128
        }
129

130
        values.add(item);
5 ✔
131

132
        if (itemType == Type.ANY_TYPE) {
4 ✔
133
            itemType = item.getType();
4 ✔
134
        } else if (itemType != item.getType()) {
6 ✔
135
            itemType = Type.getCommonSuperType(item.getType(), itemType);
7 ✔
136
        }
137

138
        setHasChanged();
2 ✔
139
    }
1 ✔
140

141
    private void addAll(final List<Item> items, @Nullable final Integer knownType) {
142
        if (!items.isEmpty()) {
×
143
            if (hasOne) {
×
144
                hasOne = false;
×
145
            }
146
            if (isEmpty) {
×
147
                isEmpty = false;
×
148
                hasOne = true;
×
149
            }
150

151
            values.addAll(items);
×
152

153
            if (knownType != null) {
×
154
                if (itemType == Type.ANY_TYPE) {
×
155
                    itemType = knownType;
×
156
                } else if (itemType != knownType) {
×
157
                    itemType = Type.getCommonSuperType(knownType, itemType);
×
158
                }
159
            } else {
×
160
                for (final Item item : items) {
×
161
                    if (itemType == Type.ITEM) {
×
162
                        // stop, already as loose as possible
163
                        break;
×
164
                    }
165

166
                    if (itemType == Type.ANY_TYPE) {
×
167
                        itemType = item.getType();
×
168
                    } else if (itemType != item.getType()) {
×
169
                        itemType = Type.getCommonSuperType(item.getType(), itemType);
×
170
                    }
171
                }
172
            }
173
        }
174
    }
×
175

176
    @Override
177
    public void addAll(final Sequence otherSequence) throws XPathException {
178
        if (otherSequence == null || otherSequence.isEmpty()) {
5 !
179
            return;
1 ✔
180
        }
181

182
        if (otherSequence instanceof ArrayListValueSequence other) {
3 !
183
            addAll(other.values, other.itemType);
×
184

185
        } else {
×
186
            final SequenceIterator iterator = otherSequence.iterate();
3 ✔
187
            if (iterator == null) {
2 !
188
                LOG.warn("Iterator == null: {}", otherSequence.getClass().getName());
×
189
                return;
×
190
            }
191
            while (iterator.hasNext()) {
3 ✔
192
                add(iterator.nextItem());
4 ✔
193
            }
194
        }
195

196
        setHasChanged();
2 ✔
197
    }
1 ✔
198

199
    @Override
200
    public int getItemType() {
201
        return itemType == Type.ANY_TYPE ? Type.ITEM : itemType;
9 ✔
202
    }
203

204
    @Override
205
    public SequenceIterator iterate() {
206
        return new ArrayListValueSequenceIterator(values.iterator());
7 ✔
207
    }
208

209
    @Override
210
    public SequenceIterator unorderedIterator() {
211
        return new ArrayListValueSequenceIterator(values.iterator());
×
212
    }
213

214
    @Override
215
    public long getItemCountLong() {
216
        return values.size();
5 ✔
217
    }
218

219
    @Override
220
    public Item itemAt(final int pos) {
221
        return values.get(pos);
6 ✔
222
    }
223

224
    @Override
225
    public boolean isPersistentSet() {
226
        if (isEmpty) {
×
227
            return true;
×
228
        }
229

230
        if (itemType != Type.ANY_TYPE && Type.subTypeOf(itemType, Type.NODE)) {
×
231
            for (final Item value : values) {
×
232
                if (((NodeValue)value).getImplementationType() != NodeValue.PERSISTENT_NODE) {
×
233
                    return false;
×
234
                }
235
            }
236
            return true;
×
237
        }
238

239
        return false;
×
240
    }
241

242
    @Override
243
    public boolean containsReference(final Item item) {
244
        for (final Item value : values) {
12 ✔
245
            // recurse into container items (maps/arrays) so a value nested inside a map or array held
246
            // by this sequence is detected, mirroring MapType/ArrayType.containsReference
247
            if (value == item || (value instanceof Sequence seq && seq.containsReference(item))) {
13 !
248
                return true;
2 ✔
249
            }
250
        }
251
        return false;
2 ✔
252
    }
253

254
    @Override
255
    public boolean contains(final Item item) {
256
        return values.contains(item);
×
257
    }
258

259
    @Override
260
    public void destroy(final XQueryContext context, @Nullable final Sequence contextSequence) {
261
        for (final Item value : values) {
12 ✔
262
            value.destroy(context, contextSequence);
4 ✔
263
        }
264
    }
1 ✔
265

266
    @Override
267
    public void removeDuplicates() {
268
        final List<Item> newValues = new ArrayList<>(values.size());
×
269
        int newType = Type.ANY_TYPE;
×
270

271
        final ItemComparator itemComparator = new ItemComparator();
×
272

273
        for (int i = 0; i < values.size(); i++) {
×
274
            final Item value = values.get(i);
×
275
            boolean foundDuplicate = false;
×
276

277
            if (Type.subTypeOf(value.getType(), Type.NODE)) {
×
278
                // look for a duplicate node
279
                for (int j = i + 1; j < values.size(); j++) {
×
280
                    final Item otherValue = values.get(j);
×
281
                    if (Type.subTypeOf(otherValue.getType(), Type.NODE)) {
×
282
                        if (itemComparator.compare(value, otherValue) == 0) {
×
283
                            foundDuplicate = true;
×
284
                            break;  // exit j loop
×
285
                        }
286
                    }
287
                }
288
            }
289

290
            if (!foundDuplicate) {
×
291
                newValues.add(value);
×
292
                if (newType == Type.ANY_TYPE) {
×
293
                    newType = value.getType();
×
294
                } else if (newType != value.getType()) {
×
295
                    newType = Type.getCommonSuperType(value.getType(), newType);
×
296
                }
297
            }
298
        }
299

300
        values.clear();
×
301
        addAll(newValues, newType);
×
302
        setHasChanged();
×
303
    }
×
304

305
    @Override
306
    public void clearContext(final int contextId) throws XPathException {
307
        for (final Item value : values) {
12 ✔
308
            if (Type.subTypeOf(value.getType(), Type.NODE)) {
5 !
309
                ((NodeValue) value).clearContext(contextId);
×
310
            }
311
        }
312
    }
1 ✔
313

314
    private void setHasChanged() {
315
        state = (state == Integer.MAX_VALUE ? state = 1 : state + 1);
10 !
316
    }
1 ✔
317

318
    @Override
319
    public int getState() {
320
        return state;
×
321
    }
322

323
    @Override
324
    public boolean hasChanged(final int previousState) {
325
        return state != previousState;
×
326
    }
327

328
    @Override
329
    public boolean isCacheable() {
330
        return true;
2 ✔
331
    }
332

333
    @Override
334
    public NodeSet toNodeSet() throws XPathException {
335
        if (isEmpty) {
×
336
            return NodeSet.EMPTY_SET;
×
337
        }
338

339
        // for this method to work, all items have to be nodes
340
        if (itemType != Type.ANY_TYPE && Type.subTypeOf(itemType, Type.NODE)) {
×
341
            final NodeSet set = new NewArrayNodeSet();
×
342
            for (int i = 0; i <= values.size(); i++) {
×
343
                NodeValue v = (NodeValue) values.get(i);
×
344
                if (v.getImplementationType() != NodeValue.PERSISTENT_NODE) {
×
345
                    // found an in-memory document
346
                    final DocumentImpl doc;
347
                    if (v.getType() == Type.DOCUMENT) {
×
348
                        doc = (DocumentImpl) v;
×
349
                    } else {
×
350
                        doc = ((NodeImpl) v).getOwnerDocument();
×
351
                    }
352

353
                    if (doc == null) {
×
354
                        continue;
×
355
                    }
356
                    // make this document persistent: doc.makePersistent()
357
                    // returns a map of all root node ids mapped to the corresponding
358
                    // persistent node. We scan the current sequence and replace all
359
                    // in-memory nodes with their new persistent node objects.
360
                    final DocumentImpl expandedDoc = doc.expandRefs(null);
×
361
                    final org.exist.dom.persistent.DocumentImpl newDoc = expandedDoc.makePersistent();
×
362
                    if (newDoc != null) {
×
363
                        NodeId rootId = newDoc.getBrokerPool().getNodeFactory().createInstance();
×
364
                        for (int j = i; j <= values.size(); j++) {
×
365
                            v = (NodeValue) values.get(j);
×
366
                            if (v.getImplementationType() != NodeValue.PERSISTENT_NODE) {
×
367
                                NodeImpl node = (NodeImpl) v;
×
368
                                final Document nodeOwnerDoc;
369
                                if (node.getNodeType() == Node.DOCUMENT_NODE) {
×
370
                                    nodeOwnerDoc = (Document) node;
×
371
                                } else {
×
372
                                    nodeOwnerDoc = node.getOwnerDocument();
×
373
                                }
374

375
                                if (nodeOwnerDoc == doc) {
×
376
                                    if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
×
377
                                        node = expandedDoc.getAttribute(node.getNodeNumber());
×
378
                                    } else {
×
379
                                        node = expandedDoc.getNode(node.getNodeNumber());
×
380
                                    }
381
                                    NodeId nodeId = node.getNodeId();
×
382
                                    if (nodeId == null) {
×
383
                                        throw new XPathException((Expression) null, "Internal error: nodeId == null");
×
384
                                    }
385
                                    if (node.getNodeType() == Node.DOCUMENT_NODE) {
×
386
                                        nodeId = rootId;
×
387
                                    } else {
×
388
                                        nodeId = rootId.append(nodeId);
×
389
                                    }
390
                                    final NodeProxy p = new NodeProxy(node.getExpression(), newDoc, nodeId, node.getNodeType());
×
391
                                    // replace the node by the NodeProxy
392
                                    values.set(j, p);
×
393

394
                                    setHasChanged();
×
395
                                }
396
                            }
397
                        }
398
                        set.add((NodeProxy) values.get(i));
×
399
                    }
400
                } else {
×
401
                    set.add((NodeProxy) v);
×
402
                }
403
            }
404
            return set;
×
405
        } else {
406
            throw new XPathException((Expression) null, ErrorCodes.XPTY0019, "Type error: the sequence cannot be converted into" +
×
407
                    " a node set. Item type is " + Type.getTypeName(itemType));
×
408
        }
409
    }
410

411
    @Override
412
    public MemoryNodeSet toMemNodeSet() throws XPathException {
413
        if (isEmpty) {
×
414
            return MemoryNodeSet.EMPTY;
×
415
        }
416

417
        if (itemType == Type.ANY_TYPE || !Type.subTypeOf(itemType, Type.NODE)) {
×
418
            throw new XPathException((Expression) null, ErrorCodes.XPTY0019, "Type error: the sequence cannot be converted into" +
×
419
                    " a node set. Item type is " + Type.getTypeName(itemType));
×
420
        }
421
        for (final Item value : values) {
×
422
            final NodeValue v = (NodeValue) value;
×
423
            if (v.getImplementationType() == NodeValue.PERSISTENT_NODE) {
×
424
                throw new XPathException((Expression) null, "Type error: the sequence cannot be converted into" +
×
425
                        " a MemoryNodeSet. It contains nodes from stored resources.");
426
            }
427
        }
428
        expand();
×
429
        return this;
×
430
    }
431

432
    /**
433
     * Scan the sequence and check all in-memory documents.
434
     * They may contains references to nodes stored in the database.
435
     * Expand those references to get a pure in-memory DOM tree.
436
     */
437
    private void expand() {
438
        final Set<DocumentImpl> docs = new HashSet<>();
×
439
        for (final Item value : values) {
×
440
            final NodeImpl node = (NodeImpl) value;
×
441
            final DocumentImpl ownerDoc = node.getNodeType() == Node.DOCUMENT_NODE ? (DocumentImpl) node : node.getOwnerDocument();
×
442

443
            if (ownerDoc.hasReferenceNodes()) {
×
444
                docs.add(ownerDoc);
×
445
            }
446
        }
447
        for (final DocumentImpl doc : docs) {
×
448
            doc.expand();
×
449
        }
450
    }
×
451

452
    private static class ArrayListValueSequenceIterator implements SequenceIterator {
453
        private final Iterator<Item> iterator;
454

455
        public ArrayListValueSequenceIterator(final Iterator<Item> iterator) {
2 ✔
456
            this.iterator = iterator;
3 ✔
457
        }
1 ✔
458

459
        @Override
460
        public boolean hasNext() {
461
            return iterator.hasNext();
4 ✔
462
        }
463

464
        @Override
465
        public Item nextItem() {
466
            if (!hasNext()) {
3 ✔
467
                return null;
2 ✔
468
            }
469
            return iterator.next();
5 ✔
470
        }
471
    }
472

473
    // <editor-fold desc="Methods of MemoryNodeSet">
474
    @Override
475
    public Sequence getAttributes(final NodeTest test) throws XPathException {
476
        final ArrayListValueSequence nodes = new ArrayListValueSequence();
×
477
        for (final Item value : values) {
×
478
            final NodeImpl node = (NodeImpl) value;
×
479
            node.selectAttributes(test, nodes);
×
480
        }
481
        return nodes;
×
482
    }
483

484
    @Override
485
    public Sequence getDescendantAttributes(final NodeTest test) throws XPathException {
486
        final ArrayListValueSequence nodes = new ArrayListValueSequence();
×
487
        for (final Item value : values) {
×
488
            final NodeImpl node = (NodeImpl) value;
×
489
            node.selectDescendantAttributes(test, nodes);
×
490
        }
491
        return nodes;
×
492
    }
493

494
    @Override
495
    public Sequence getChildren(final NodeTest test) throws XPathException {
496
        final ArrayListValueSequence nodes = new ArrayListValueSequence();
×
497
        for (final Item value : values) {
×
498
            final NodeImpl node = (NodeImpl) value;
×
499
            node.selectChildren(test, nodes);
×
500
        }
501
        return nodes;
×
502
    }
503

504
    @Override
505
    public Sequence getChildrenForParent(final NodeImpl parent) {
506
        final ArrayListValueSequence nodes = new ArrayListValueSequence();
×
507
        for (final Item value : values) {
×
508
            final NodeImpl node = (NodeImpl) value;
×
509
            if (node.getNodeId().isChildOf(parent.getNodeId())) {
×
510
                nodes.add(node);
×
511
            }
512
        }
513
        return nodes;
×
514
    }
515

516
    @Override
517
    public Sequence getDescendants(final boolean includeSelf, final NodeTest test) throws XPathException {
518
        final ArrayListValueSequence nodes = new ArrayListValueSequence();
×
519
        for (final Item value : values) {
×
520
            final NodeImpl node = (NodeImpl) value;
×
521
            node.selectDescendants(includeSelf, test, nodes);
×
522
        }
523
        return nodes;
×
524
    }
525

526
    @Override
527
    public Sequence getAncestors(final boolean includeSelf, final NodeTest test) throws XPathException {
528
        final ArrayListValueSequence nodes = new ArrayListValueSequence();
×
529
        for (final Item value : values) {
×
530
            final NodeImpl node = (NodeImpl) value;
×
531
            node.selectAncestors(includeSelf, test, nodes);
×
532
        }
533
        return nodes;
×
534
    }
535

536
    @Override
537
    public Sequence getParents(final NodeTest test) throws XPathException {
538
        final ArrayListValueSequence nodes = new ArrayListValueSequence();
×
539
        for (final Item value : values) {
×
540
            final NodeImpl node = (NodeImpl) value;
×
541
            final NodeImpl parent = (NodeImpl) node.selectParentNode();
×
542
            if (parent != null && test.matches(parent)) {
×
543
                nodes.add(parent);
×
544
            }
545
        }
546
        return nodes;
×
547
    }
548

549
    @Override
550
    public Sequence getSelf(final NodeTest test) throws XPathException {
551
        final ArrayListValueSequence nodes = new ArrayListValueSequence();
×
552
        for (final Item value : values) {
×
553
            final NodeImpl node = (NodeImpl) value;
×
554
            if ((test.getType() == Type.NODE && node.getNodeType() == Node.ATTRIBUTE_NODE) ||
×
555
                    test.matches(node)) {
×
556
                nodes.add(node);
×
557
            }
558
        }
559
        return nodes;
×
560
    }
561

562
    @Override
563
    public Sequence getPrecedingSiblings(final NodeTest test) throws XPathException {
564
        final ArrayListValueSequence nodes = new ArrayListValueSequence();
×
565
        for (final Item value : values) {
×
566
            final NodeImpl node = (NodeImpl) value;
×
567

568
            // if the context node is an attribute or namespace node, the preceding-sibling axis is empty
569
            if (node.getNodeType() != Node.ATTRIBUTE_NODE) {
×
570
                node.selectPrecedingSiblings(test, nodes);
×
571
            }
572
        }
573
        return nodes;
×
574
    }
575

576
    @Override
577
    public Sequence getPreceding(final NodeTest test, final int position) throws XPathException {
578
        final ArrayListValueSequence nodes = new ArrayListValueSequence();
×
579
        for (final Item value : values) {
×
580
            final NodeImpl node = (NodeImpl) value;
×
581
            node.selectPreceding(test, nodes, position);
×
582
        }
583
        return nodes;
×
584
    }
585

586
    @Override
587
    public Sequence getFollowingSiblings(final NodeTest test) throws XPathException {
588
        final ArrayListValueSequence nodes = new ArrayListValueSequence();
×
589
        for (final Item value : values) {
×
590
            final NodeImpl node = (NodeImpl) value;
×
591
            // if the context node is an attribute or namespace node, the following-sibling axis is empty
592
            if (node.getNodeType() != Node.ATTRIBUTE_NODE) {
×
593
                node.selectFollowingSiblings(test, nodes);
×
594
            }
595
        }
596
        return nodes;
×
597
    }
598

599
    @Override
600
    public Sequence getFollowing(final NodeTest test, final int position) throws XPathException {
601
        final ArrayListValueSequence nodes = new ArrayListValueSequence();
×
602
        for (final Item value : values) {
×
603
            final NodeImpl node = (NodeImpl) value;
×
604
            node.selectFollowing(test, nodes, position);
×
605
        }
606
        return nodes;
×
607
    }
608

609
    @Override
610
    public Sequence selectDescendants(final MemoryNodeSet descendants) {
611
        final ArrayListValueSequence nodes = new ArrayListValueSequence();
×
612
        for (final Item value : values) {
×
613
            final NodeImpl node = (NodeImpl) value;
×
614
            for (int j = 0; j < descendants.size(); j++) {
×
615
                final NodeImpl descendant = descendants.get(j);
×
616
                if (descendant.getNodeId().isDescendantOrSelfOf(node.getNodeId())) {
×
617
                    nodes.add(node);
×
618
                }
619
            }
620
        }
621
        return nodes;
×
622
    }
623

624
    @Override
625
    public Sequence selectChildren(final MemoryNodeSet children) {
626
        final ArrayListValueSequence nodes = new ArrayListValueSequence();
×
627
        for (final Item value : values) {
×
628
            final NodeImpl node = (NodeImpl) value;
×
629
            for (int j = 0; j < children.size(); j++) {
×
630
                final NodeImpl descendant = children.get(j);
×
631
                if (descendant.getNodeId().isChildOf(node.getNodeId())) {
×
632
                    nodes.add(node);
×
633
                }
634
            }
635
        }
636
        return nodes;
×
637
    }
638

639

640
    @Override
641
    public boolean matchSelf(final NodeTest test) {
642
        for (final Item value : values) {
×
643
            final NodeImpl node = (NodeImpl) value;
×
644
            if ((test.getType() == Type.NODE && node.getNodeType() == Node.ATTRIBUTE_NODE) ||
×
645
                    test.matches(node)) {
×
646
                return true;
×
647
            }
648
        }
649
        return false;
×
650
    }
651

652
    @Override
653
    public boolean matchChildren(final NodeTest test) throws XPathException {
654
        for (final Item value : values) {
×
655
            final NodeImpl node = (NodeImpl) value;
×
656
            if (node.matchChildren(test)) {
×
657
                return true;
×
658
            }
659
        }
660
        return false;
×
661
    }
662

663
    @Override
664
    public boolean matchAttributes(final NodeTest test) {
665
        for (final Item value : values) {
×
666
            final NodeImpl node = (NodeImpl) value;
×
667
            if (node.matchAttributes(test)) {
×
668
                return true;
×
669
            }
670
        }
671
        return false;
×
672
    }
673

674
    @Override
675
    public boolean matchDescendantAttributes(final NodeTest test) throws XPathException {
676
        for (final Item value : values) {
×
677
            final NodeImpl node = (NodeImpl) value;
×
678
            if (node.matchDescendantAttributes(test)) {
×
679
                return true;
×
680
            }
681
        }
682
        return false;
×
683
    }
684

685
    @Override
686
    public int size() {
687
        return values.size();
×
688
    }
689

690
    @Override
691
    public NodeImpl get(final int which) {
692
        return (NodeImpl) values.get(which);
×
693
    }
694

695
    // </editor-fold>
696
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc