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

evolvedbinary / elemental / 982

29 Apr 2025 08:34PM UTC coverage: 56.409% (+0.007%) from 56.402%
982

push

circleci

adamretter
[feature] Improve README.md badges

28451 of 55847 branches covered (50.94%)

Branch coverage included in aggregate %.

77468 of 131924 relevant lines covered (58.72%)

0.59 hits per line

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

15.47
/exist-core/src/main/java/org/exist/xquery/value/ArrayListValueSequence.java
1
/*
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
 * Use of this software is governed by the Business Source License 1.1
9
 * included in the LICENSE file and at www.mariadb.com/bsl11.
10
 *
11
 * Change Date: 2028-04-27
12
 *
13
 * On the date above, in accordance with the Business Source License, use
14
 * of this software will be governed by the Apache License, Version 2.0.
15
 *
16
 * Additional Use Grant: Production use of the Licensed Work for a permitted
17
 * purpose. A Permitted Purpose is any purpose other than a Competing Use.
18
 * A Competing Use means making the Software available to others in a commercial
19
 * product or service that: substitutes for the Software; substitutes for any
20
 * other product or service we offer using the Software that exists as of the
21
 * date we make the Software available; or offers the same or substantially
22
 * similar functionality as the Software.
23
 */
24
package org.exist.xquery.value;
25

26
import org.apache.logging.log4j.LogManager;
27
import org.apache.logging.log4j.Logger;
28
import org.exist.dom.memtree.DocumentImpl;
29
import org.exist.dom.memtree.NodeImpl;
30
import org.exist.dom.persistent.NewArrayNodeSet;
31
import org.exist.dom.persistent.NodeProxy;
32
import org.exist.dom.persistent.NodeSet;
33
import org.exist.numbering.NodeId;
34
import org.exist.xquery.Expression;
35
import org.exist.xquery.NodeTest;
36
import org.exist.xquery.XPathException;
37
import org.exist.xquery.XQueryContext;
38
import org.w3c.dom.Document;
39
import org.w3c.dom.Node;
40

41
import javax.annotation.Nullable;
42
import java.util.*;
43

44
/**
45
 * Alternative to {@link ValueSequence}, this version
46
 * is much faster, but it does not support sorting!
47
 *
48
 * @author <a href="mailto:adam@evolvedbinary.com">Adam Retter</a>
49
 */
50
public class ArrayListValueSequence extends AbstractSequence implements MemoryNodeSet {
51

52
    private final static Logger LOG = LogManager.getLogger(ArrayListValueSequence.class);
1✔
53

54
    private final List<Item> values;
55

56
    // used to keep track of the type of added items.
57
    // will be Type.ANY_TYPE if the type is unknown
58
    // and Type.ITEM if there are items of mixed type.
59
    private int itemType = Type.ANY_TYPE;
1✔
60

61
    private int state = 0;
1✔
62

63
    public ArrayListValueSequence() {
1✔
64
        this.isEmpty = true;
1✔
65
        this.hasOne = false;
1✔
66
        this.values = new ArrayList<>();
1✔
67
    }
1✔
68

69
    public ArrayListValueSequence(final int initialSize) {
1✔
70
        this.isEmpty = true;
1✔
71
        this.hasOne = false;
1✔
72
        this.values = new ArrayList<>(initialSize);
1✔
73
    }
1✔
74

75
    public ArrayListValueSequence(final Sequence otherSequence) throws XPathException {
×
76
        this.isEmpty = true;
×
77
        this.hasOne = false;
×
78
        this.values = new ArrayList<>(otherSequence.getItemCount());
×
79
        addAll(otherSequence);
×
80
    }
×
81

82
    public ArrayListValueSequence(final Item... items) {
×
83
        this.isEmpty = true;
×
84
        this.hasOne = false;
×
85
        this.values = new ArrayList<>(items.length);
×
86
        addAll(Arrays.asList(items), null);
×
87
    }
×
88

89
    public void clear() {
90
        if (!isEmpty) {
×
91
            setHasChanged();
×
92
        }
93

94
        values.clear();
×
95
        this.itemType = Type.ANY_TYPE;
×
96
        this.isEmpty = true;
×
97
        this.hasOne = false;
×
98
    }
×
99

100
    @Override
101
    public boolean isEmpty() {
102
        return isEmpty;
1✔
103
    }
104

105
    @Override
106
    public boolean hasOne() {
107
        return hasOne;
1✔
108
    }
109

110
    @Override
111
    public void add(final Item item) {
112
        if (hasOne) {
1✔
113
            hasOne = false;
1✔
114
        }
115
        if (isEmpty) {
1✔
116
            isEmpty = false;
1✔
117
            hasOne = true;
1✔
118
        }
119

120
        values.add(item);
1✔
121

122
        if (itemType == Type.ANY_TYPE) {
1✔
123
            itemType = item.getType();
1✔
124
        } else if (itemType != item.getType()) {
1✔
125
            itemType = Type.getCommonSuperType(item.getType(), itemType);
1✔
126
        }
127

128
        setHasChanged();
1✔
129
    }
1✔
130

131
    private void addAll(final List<Item> items, @Nullable final Integer knownType) {
132
        if (!items.isEmpty()) {
×
133
            if (hasOne) {
×
134
                hasOne = false;
×
135
            }
136
            if (isEmpty) {
×
137
                isEmpty = false;
×
138
                hasOne = true;
×
139
            }
140

141
            values.addAll(items);
×
142

143
            if (knownType != null) {
×
144
                if (itemType == Type.ANY_TYPE) {
×
145
                    itemType = knownType;
×
146
                } else if (itemType != knownType) {
×
147
                    itemType = Type.getCommonSuperType(knownType, itemType);
×
148
                }
149
            } else {
×
150
                for (final Item item : items) {
×
151
                    if (itemType == Type.ITEM) {
×
152
                        // stop, already as loose as possible
153
                        break;
×
154
                    }
155

156
                    if (itemType == Type.ANY_TYPE) {
×
157
                        itemType = item.getType();
×
158
                    } else if (itemType != item.getType()) {
×
159
                        itemType = Type.getCommonSuperType(item.getType(), itemType);
×
160
                    }
161
                }
162
            }
163
        }
164
    }
×
165

166
    @Override
167
    public void addAll(final Sequence otherSequence) throws XPathException {
168
        if (otherSequence == null || otherSequence.isEmpty()) {
1!
169
            return;
1✔
170
        }
171

172
        if (otherSequence instanceof ArrayListValueSequence other) {
1!
173
            addAll(other.values, other.itemType);
×
174

175
        } else {
×
176
            final SequenceIterator iterator = otherSequence.iterate();
1✔
177
            if (iterator == null) {
1!
178
                LOG.warn("Iterator == null: {}", otherSequence.getClass().getName());
×
179
                return;
×
180
            }
181
            while (iterator.hasNext()) {
1✔
182
                add(iterator.nextItem());
1✔
183
            }
184
        }
185

186
        setHasChanged();
1✔
187
    }
1✔
188

189
    @Override
190
    public int getItemType() {
191
        return itemType == Type.ANY_TYPE ? Type.ITEM : itemType;
1✔
192
    }
193

194
    @Override
195
    public SequenceIterator iterate() {
196
        return new ArrayListValueSequenceIterator(values.iterator());
1✔
197
    }
198

199
    @Override
200
    public SequenceIterator unorderedIterator() {
201
        return new ArrayListValueSequenceIterator(values.iterator());
×
202
    }
203

204
    @Override
205
    public long getItemCountLong() {
206
        return values.size();
1✔
207
    }
208

209
    @Override
210
    public Item itemAt(final int pos) {
211
        return values.get(pos);
1✔
212
    }
213

214
    @Override
215
    public boolean isPersistentSet() {
216
        if (isEmpty) {
×
217
            return true;
×
218
        }
219

220
        if (itemType != Type.ANY_TYPE && Type.subTypeOf(itemType, Type.NODE)) {
×
221
            for (final Item value : values) {
×
222
                if (((NodeValue)value).getImplementationType() != NodeValue.PERSISTENT_NODE) {
×
223
                    return false;
×
224
                }
225
            }
226
            return true;
×
227
        }
228

229
        return false;
×
230
    }
231

232
    @Override
233
    public boolean containsReference(final Item item) {
234
        for (final Iterator<Item> it = values.iterator(); it.hasNext(); ) {
×
235
            final Item value = it.next();
×
236
            if (value == item) {
×
237
                return true;
×
238
            }
239
        }
240
        return false;
×
241
    }
242

243
    @Override
244
    public boolean contains(final Item item) {
245
        return values.contains(item);
×
246
    }
247

248
    @Override
249
    public void destroy(final XQueryContext context, @Nullable final Sequence contextSequence) {
250
        for (final Item value : values) {
1✔
251
            value.destroy(context, contextSequence);
1✔
252
        }
253
    }
1✔
254

255
    @Override
256
    public void removeDuplicates() {
257
        final List<Item> newValues = new ArrayList<>(values.size());
×
258
        int newType = Type.ANY_TYPE;
×
259

260
        final ItemComparator itemComparator = new ItemComparator();
×
261

262
        for (int i = 0; i < values.size(); i++) {
×
263
            final Item value = values.get(i);
×
264
            boolean foundDuplicate = false;
×
265

266
            if (Type.subTypeOf(value.getType(), Type.NODE)) {
×
267
                // look for a duplicate node
268
                for (int j = i + 1; j < values.size(); j++) {
×
269
                    final Item otherValue = values.get(j);
×
270
                    if (Type.subTypeOf(otherValue.getType(), Type.NODE)) {
×
271
                        if (itemComparator.compare(value, otherValue) == 0) {
×
272
                            foundDuplicate = true;
×
273
                            break;  // exit j loop
×
274
                        }
275
                    }
276
                }
277
            }
278

279
            if (!foundDuplicate) {
×
280
                newValues.add(value);
×
281
                if (newType == Type.ANY_TYPE) {
×
282
                    newType = value.getType();
×
283
                } else if (newType != value.getType()) {
×
284
                    newType = Type.getCommonSuperType(value.getType(), newType);
×
285
                }
286
            }
287
        }
288

289
        values.clear();
×
290
        addAll(newValues, newType);
×
291
        setHasChanged();
×
292
    }
×
293

294
    @Override
295
    public void clearContext(final int contextId) throws XPathException {
296
        for (final Item value : values) {
1✔
297
            if (Type.subTypeOf(value.getType(), Type.NODE)) {
1✔
298
                ((NodeValue) value).clearContext(contextId);
1✔
299
            }
300
        }
301
    }
1✔
302

303
    private void setHasChanged() {
304
        state = (state == Integer.MAX_VALUE ? state = 1 : state + 1);
1!
305
    }
1✔
306

307
    @Override
308
    public int getState() {
309
        return state;
×
310
    }
311

312
    @Override
313
    public boolean hasChanged(final int previousState) {
314
        return state != previousState;
×
315
    }
316

317
    @Override
318
    public boolean isCacheable() {
319
        return true;
×
320
    }
321

322
    @Override
323
    public NodeSet toNodeSet() throws XPathException {
324
        if (isEmpty) {
×
325
            return NodeSet.EMPTY_SET;
×
326
        }
327

328
        // for this method to work, all items have to be nodes
329
        if (itemType != Type.ANY_TYPE && Type.subTypeOf(itemType, Type.NODE)) {
×
330
            final NodeSet set = new NewArrayNodeSet();
×
331
            for (int i = 0; i <= values.size(); i++) {
×
332
                NodeValue v = (NodeValue) values.get(i);
×
333
                if (v.getImplementationType() != NodeValue.PERSISTENT_NODE) {
×
334
                    // found an in-memory document
335
                    final DocumentImpl doc;
336
                    if (v.getType() == Type.DOCUMENT) {
×
337
                        doc = (DocumentImpl) v;
×
338
                    } else {
×
339
                        doc = ((NodeImpl) v).getOwnerDocument();
×
340
                    }
341

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

364
                                if (nodeOwnerDoc == doc) {
×
365
                                    if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
×
366
                                        node = expandedDoc.getAttribute(node.getNodeNumber());
×
367
                                    } else {
×
368
                                        node = expandedDoc.getNode(node.getNodeNumber());
×
369
                                    }
370
                                    NodeId nodeId = node.getNodeId();
×
371
                                    if (nodeId == null) {
×
372
                                        throw new XPathException((Expression) null, "Internal error: nodeId == null");
×
373
                                    }
374
                                    if (node.getNodeType() == Node.DOCUMENT_NODE) {
×
375
                                        nodeId = rootId;
×
376
                                    } else {
×
377
                                        nodeId = rootId.append(nodeId);
×
378
                                    }
379
                                    final NodeProxy p = new NodeProxy(node.getExpression(), newDoc, nodeId, node.getNodeType());
×
380
                                    // replace the node by the NodeProxy
381
                                    values.set(j, p);
×
382

383
                                    setHasChanged();
×
384
                                }
385
                            }
386
                        }
387
                        set.add((NodeProxy) values.get(i));
×
388
                    }
389
                } else {
×
390
                    set.add((NodeProxy) v);
×
391
                }
392
            }
393
//            if (holderVar != null) {
394
//                holderVar.setValue(set);
395
//            }
396
            return set;
×
397
        } else {
398
            throw new XPathException((Expression) null, "Type error: the sequence cannot be converted into" +
×
399
                    " a node set. Item type is " + Type.getTypeName(itemType));
×
400
        }
401
    }
402

403
    @Override
404
    public MemoryNodeSet toMemNodeSet() throws XPathException {
405
        if (isEmpty) {
×
406
            return MemoryNodeSet.EMPTY;
×
407
        }
408

409
        if (itemType == Type.ANY_TYPE || !Type.subTypeOf(itemType, Type.NODE)) {
×
410
            throw new XPathException((Expression) null, "Type error: the sequence cannot be converted into" +
×
411
                    " a node set. Item type is " + Type.getTypeName(itemType));
×
412
        }
413
        for (final Item value : values) {
×
414
            final NodeValue v = (NodeValue) value;
×
415
            if (v.getImplementationType() == NodeValue.PERSISTENT_NODE) {
×
416
                throw new XPathException((Expression) null, "Type error: the sequence cannot be converted into" +
×
417
                        " a MemoryNodeSet. It contains nodes from stored resources.");
418
            }
419
        }
420
        expand();
×
421
        return this;
×
422
    }
423

424
    /**
425
     * Scan the sequence and check all in-memory documents.
426
     * They may contains references to nodes stored in the database.
427
     * Expand those references to get a pure in-memory DOM tree.
428
     */
429
    private void expand() {
430
        final Set<DocumentImpl> docs = new HashSet<>();
×
431
        for (final Item value : values) {
×
432
            final NodeImpl node = (NodeImpl) value;
×
433
            final DocumentImpl ownerDoc = node.getNodeType() == Node.DOCUMENT_NODE ? (DocumentImpl) node : node.getOwnerDocument();
×
434

435
            if (ownerDoc.hasReferenceNodes()) {
×
436
                docs.add(ownerDoc);
×
437
            }
438
        }
439
        for (final DocumentImpl doc : docs) {
×
440
            doc.expand();
×
441
        }
442
    }
×
443

444
    private static class ArrayListValueSequenceIterator implements SequenceIterator {
445
        private final Iterator<Item> iterator;
446

447
        public ArrayListValueSequenceIterator(final Iterator<Item> iterator) {
1✔
448
            this.iterator = iterator;
1✔
449
        }
1✔
450

451
        @Override
452
        public boolean hasNext() {
453
            return iterator.hasNext();
1✔
454
        }
455

456
        @Override
457
        public Item nextItem() {
458
            if (!hasNext()) {
1!
459
                return null;
×
460
            }
461
            return iterator.next();
1✔
462
        }
463
    }
464

465
    // <editor-fold desc="Methods of MemoryNodeSet">
466
    @Override
467
    public Sequence getAttributes(final NodeTest test) throws XPathException {
468
        final ArrayListValueSequence nodes = new ArrayListValueSequence();
×
469
        for (final Item value : values) {
×
470
            final NodeImpl node = (NodeImpl) value;
×
471
            node.selectAttributes(test, nodes);
×
472
        }
473
        return nodes;
×
474
    }
475

476
    @Override
477
    public Sequence getDescendantAttributes(final NodeTest test) throws XPathException {
478
        final ArrayListValueSequence nodes = new ArrayListValueSequence();
×
479
        for (final Item value : values) {
×
480
            final NodeImpl node = (NodeImpl) value;
×
481
            node.selectDescendantAttributes(test, nodes);
×
482
        }
483
        return nodes;
×
484
    }
485

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

496
    @Override
497
    public Sequence getChildrenForParent(final NodeImpl parent) {
498
        final ArrayListValueSequence nodes = new ArrayListValueSequence();
×
499
        for (final Item value : values) {
×
500
            final NodeImpl node = (NodeImpl) value;
×
501
            if (node.getNodeId().isChildOf(parent.getNodeId())) {
×
502
                nodes.add(node);
×
503
            }
504
        }
505
        return nodes;
×
506
    }
507

508
    @Override
509
    public Sequence getDescendants(final boolean includeSelf, final NodeTest test) throws XPathException {
510
        final ArrayListValueSequence nodes = new ArrayListValueSequence();
×
511
        for (final Item value : values) {
×
512
            final NodeImpl node = (NodeImpl) value;
×
513
            node.selectDescendants(includeSelf, test, nodes);
×
514
        }
515
        return nodes;
×
516
    }
517

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

528
    @Override
529
    public Sequence getParents(final NodeTest test) throws XPathException {
530
        final ArrayListValueSequence nodes = new ArrayListValueSequence();
×
531
        for (final Item value : values) {
×
532
            final NodeImpl node = (NodeImpl) value;
×
533
            final NodeImpl parent = (NodeImpl) node.selectParentNode();
×
534
            if (parent != null && test.matches(parent)) {
×
535
                nodes.add(parent);
×
536
            }
537
        }
538
        return nodes;
×
539
    }
540

541
    @Override
542
    public Sequence getSelf(final NodeTest test) throws XPathException {
543
        final ArrayListValueSequence nodes = new ArrayListValueSequence();
×
544
        for (final Item value : values) {
×
545
            final NodeImpl node = (NodeImpl) value;
×
546
            if ((test.getType() == Type.NODE && node.getNodeType() == Node.ATTRIBUTE_NODE) ||
×
547
                    test.matches(node)) {
×
548
                nodes.add(node);
×
549
            }
550
        }
551
        return nodes;
×
552
    }
553

554
    @Override
555
    public Sequence getPrecedingSiblings(final NodeTest test) throws XPathException {
556
        final ArrayListValueSequence nodes = new ArrayListValueSequence();
×
557
        for (final Item value : values) {
×
558
            final NodeImpl node = (NodeImpl) value;
×
559

560
            // if the context node is an attribute or namespace node, the preceding-sibling axis is empty
561
            if (node.getNodeType() != Node.ATTRIBUTE_NODE) {
×
562
                node.selectPrecedingSiblings(test, nodes);
×
563
            }
564
        }
565
        return nodes;
×
566
    }
567

568
    @Override
569
    public Sequence getPreceding(final NodeTest test, final int position) throws XPathException {
570
        final ArrayListValueSequence nodes = new ArrayListValueSequence();
×
571
        for (final Item value : values) {
×
572
            final NodeImpl node = (NodeImpl) value;
×
573
            node.selectPreceding(test, nodes, position);
×
574
        }
575
        return nodes;
×
576
    }
577

578
    @Override
579
    public Sequence getFollowingSiblings(final NodeTest test) throws XPathException {
580
        final ArrayListValueSequence nodes = new ArrayListValueSequence();
×
581
        for (final Item value : values) {
×
582
            final NodeImpl node = (NodeImpl) value;
×
583
            // if the context node is an attribute or namespace node, the following-sibling axis is empty
584
            if (node.getNodeType() != Node.ATTRIBUTE_NODE) {
×
585
                node.selectFollowingSiblings(test, nodes);
×
586
            }
587
        }
588
        return nodes;
×
589
    }
590

591
    @Override
592
    public Sequence getFollowing(final NodeTest test, final int position) throws XPathException {
593
        final ArrayListValueSequence nodes = new ArrayListValueSequence();
×
594
        for (final Item value : values) {
×
595
            final NodeImpl node = (NodeImpl) value;
×
596
            node.selectFollowing(test, nodes, position);
×
597
        }
598
        return nodes;
×
599
    }
600

601
    @Override
602
    public Sequence selectDescendants(final MemoryNodeSet descendants) {
603
        final ArrayListValueSequence nodes = new ArrayListValueSequence();
×
604
        for (final Item value : values) {
×
605
            final NodeImpl node = (NodeImpl) value;
×
606
            for (int j = 0; j < descendants.size(); j++) {
×
607
                final NodeImpl descendant = descendants.get(j);
×
608
                if (descendant.getNodeId().isDescendantOrSelfOf(node.getNodeId())) {
×
609
                    nodes.add(node);
×
610
                }
611
            }
612
        }
613
        return nodes;
×
614
    }
615

616
    @Override
617
    public Sequence selectChildren(final MemoryNodeSet children) {
618
        final ArrayListValueSequence nodes = new ArrayListValueSequence();
×
619
        for (final Item value : values) {
×
620
            final NodeImpl node = (NodeImpl) value;
×
621
            for (int j = 0; j < children.size(); j++) {
×
622
                final NodeImpl descendant = children.get(j);
×
623
                if (descendant.getNodeId().isChildOf(node.getNodeId())) {
×
624
                    nodes.add(node);
×
625
                }
626
            }
627
        }
628
        return nodes;
×
629
    }
630

631

632
    @Override
633
    public boolean matchSelf(final NodeTest test) {
634
        for (final Item value : values) {
×
635
            final NodeImpl node = (NodeImpl) value;
×
636
            if ((test.getType() == Type.NODE && node.getNodeType() == Node.ATTRIBUTE_NODE) ||
×
637
                    test.matches(node)) {
×
638
                return true;
×
639
            }
640
        }
641
        return false;
×
642
    }
643

644
    @Override
645
    public boolean matchChildren(final NodeTest test) throws XPathException {
646
        for (final Item value : values) {
×
647
            final NodeImpl node = (NodeImpl) value;
×
648
            if (node.matchChildren(test)) {
×
649
                return true;
×
650
            }
651
        }
652
        return false;
×
653
    }
654

655
    @Override
656
    public boolean matchAttributes(final NodeTest test) {
657
        for (final Item value : values) {
×
658
            final NodeImpl node = (NodeImpl) value;
×
659
            if (node.matchAttributes(test)) {
×
660
                return true;
×
661
            }
662
        }
663
        return false;
×
664
    }
665

666
    @Override
667
    public boolean matchDescendantAttributes(final NodeTest test) throws XPathException {
668
        for (final Item value : values) {
×
669
            final NodeImpl node = (NodeImpl) value;
×
670
            if (node.matchDescendantAttributes(test)) {
×
671
                return true;
×
672
            }
673
        }
674
        return false;
×
675
    }
676

677
    @Override
678
    public int size() {
679
        return values.size();
×
680
    }
681

682
    @Override
683
    public NodeImpl get(final int which) {
684
        return (NodeImpl) values.get(which);
×
685
    }
686

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

© 2025 Coveralls, Inc