• 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

59.17
/exist-core/src/main/java/org/exist/dom/memtree/NodeImpl.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
 * NOTE: Parts of this file contain code from 'The eXist-db Authors'.
25
 *       The original license header is included below.
26
 *
27
 * =====================================================================
28
 *
29
 * eXist-db Open Source Native XML Database
30
 * Copyright (C) 2001 The eXist-db Authors
31
 *
32
 * info@exist-db.org
33
 * http://www.exist-db.org
34
 *
35
 * This library is free software; you can redistribute it and/or
36
 * modify it under the terms of the GNU Lesser General Public
37
 * License as published by the Free Software Foundation; either
38
 * version 2.1 of the License, or (at your option) any later version.
39
 *
40
 * This library is distributed in the hope that it will be useful,
41
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
42
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
43
 * Lesser General Public License for more details.
44
 *
45
 * You should have received a copy of the GNU Lesser General Public
46
 * License along with this library; if not, write to the Free Software
47
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
48
 */
49
package org.exist.dom.memtree;
50

51
import org.apache.xerces.util.XML11Char;
52
import org.apache.xerces.util.XMLChar;
53
import org.exist.collections.Collection;
54
import org.exist.dom.INode;
55
import org.exist.dom.NodeListImpl;
56
import org.exist.dom.QName;
57
import org.exist.dom.persistent.DocumentSet;
58
import org.exist.dom.persistent.EmptyNodeSet;
59
import org.exist.dom.persistent.NodeHandle;
60
import org.exist.dom.persistent.NodeSet;
61
import org.exist.numbering.NodeId;
62
import org.exist.storage.DBBroker;
63
import org.exist.storage.serializers.Serializer;
64
import org.exist.util.serializer.AttrList;
65
import org.exist.util.serializer.Receiver;
66
import org.exist.xquery.*;
67
import org.exist.xquery.value.*;
68
import org.w3c.dom.*;
69
import org.xml.sax.ContentHandler;
70
import org.xml.sax.SAXException;
71
import org.xml.sax.ext.LexicalHandler;
72

73
import javax.annotation.Nullable;
74
import javax.xml.XMLConstants;
75
import java.util.Iterator;
76
import java.util.Properties;
77

78

79
public abstract class NodeImpl<T extends NodeImpl<T>> implements INode<DocumentImpl, T>, NodeValue {
80

81
    public static final short REFERENCE_NODE = 100;
82
    public static final short NAMESPACE_NODE = 101;
83

84
    protected int nodeNumber;
85
    protected DocumentImpl document;
86
    private @Nullable final Expression expression;
87

88
    public NodeImpl(final DocumentImpl doc, final int nodeNumber) {
89
        this(null, doc, nodeNumber);
×
90
    }
×
91

92
    public NodeImpl(@Nullable final Expression expression, final DocumentImpl doc, final int nodeNumber) {
1✔
93
        this.expression = expression;
1✔
94
        this.document = doc;
1✔
95
        this.nodeNumber = nodeNumber;
1✔
96
    }
1✔
97

98
    public Expression getExpression() {
99
        return expression;
1✔
100
    }
101

102
    public int getNodeNumber() {
103
        return nodeNumber;
1✔
104
    }
105

106
    @Override
107
    public int getImplementationType() {
108
        return NodeValue.IN_MEMORY_NODE;
1✔
109
    }
110

111
    @Override
112
    public DocumentSet getDocumentSet() {
113
        return DocumentSet.EMPTY_DOCUMENT_SET;
1✔
114
    }
115

116
    @Override
117
    public Iterator<Collection> getCollectionIterator() {
118
        return EmptyNodeSet.EMPTY_COLLECTION_ITERATOR;
×
119
    }
120

121
    @Override
122
    public Node getNode() {
123
        return this;
1✔
124
    }
125

126
    @Override
127
    public QName getQName() {
128
        switch(getNodeType()) {
1!
129
            case Node.ATTRIBUTE_NODE:
130
                return document.attrName[nodeNumber];
1✔
131

132
            case Node.ELEMENT_NODE:
133
            case Node.PROCESSING_INSTRUCTION_NODE:
134
                return document.nodeName[nodeNumber];
1✔
135

136
            case NodeImpl.NAMESPACE_NODE:
137
                return document.namespaceCode[nodeNumber];
1✔
138

139
            case Node.DOCUMENT_NODE:
140
                return QName.EMPTY_QNAME;
1✔
141

142
            case Node.COMMENT_NODE:
143
                return QName.EMPTY_QNAME;
×
144

145
            case Node.TEXT_NODE:
146
                return QName.EMPTY_QNAME;
1✔
147

148
            case Node.CDATA_SECTION_NODE:
149
                return QName.EMPTY_QNAME;
1✔
150

151
            default:
152
                return null;
×
153
        }
154
    }
155

156
    @Override
157
    public final void setQName(final QName qname) {
158
        switch (getNodeType()) {
×
159
            case Node.ATTRIBUTE_NODE -> document.attrName[nodeNumber] = qname;
×
160
            case Node.ELEMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE -> document.nodeName[nodeNumber] = qname;
×
161
            case NodeImpl.NAMESPACE_NODE -> document.namespaceCode[nodeNumber] = qname;
×
162
        }
163
    }
×
164

165
    @Override
166
    public final String getNodeName() {
167
        return switch (getNodeType()) {
1!
168
            case Node.DOCUMENT_NODE -> "#document";
1✔
169
            case Node.DOCUMENT_FRAGMENT_NODE -> "#document-fragment";
×
170
            case Node.ELEMENT_NODE, Node.ATTRIBUTE_NODE, NAMESPACE_NODE -> getQName().getStringValue();
1✔
171
            case Node.PROCESSING_INSTRUCTION_NODE -> ((ProcessingInstructionImpl) this).getTarget();
×
172
            case Node.TEXT_NODE -> "#text";
1✔
173
            case Node.COMMENT_NODE -> "#comment";
1✔
174
            case Node.CDATA_SECTION_NODE -> "#cdata-section";
1✔
175
            default -> "#unknown";
×
176
        };
177
    }
178

179
    @Override
180
    public String getLocalName() {
181
        return switch (getNodeType()) {
1✔
182
            case Node.ELEMENT_NODE, Node.ATTRIBUTE_NODE, NAMESPACE_NODE -> getQName().getLocalPart();
1✔
183
            default -> null;
1✔
184
        };
185
    }
186

187
    @Override
188
    public String getNamespaceURI() {
189
        return switch (getNodeType()) {
1✔
190
            case Node.ELEMENT_NODE, Node.ATTRIBUTE_NODE -> {
191
                final String nsUri = getQName().getNamespaceURI();
1✔
192
                if (nsUri.equals(XMLConstants.NULL_NS_URI)) {
1✔
193
                    yield null;
1✔
194
                } else {
195
                    yield nsUri;
1✔
196
                }
197
            }
198
            case NodeImpl.NAMESPACE_NODE -> XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
1✔
199
            default -> null;
1✔
200
        };
201
    }
202

203
    @Override
204
    public final String getPrefix() {
205
        return switch (getNodeType()) {
1✔
206
            case Node.ELEMENT_NODE, Node.ATTRIBUTE_NODE, NodeImpl.NAMESPACE_NODE -> getQName().getPrefix();
1✔
207
            default -> null;
1✔
208
        };
209
    }
210

211
    @Override
212
    public void setPrefix(final String prefix) throws DOMException {
213
        if(prefix == null || getNodeType() == Node.DOCUMENT_NODE) {
×
214
            return;
×
215
        } else if(getOwnerDocument().getXmlVersion().equals("1.0") && !XMLChar.isValidNCName(prefix)) {
×
216
            throw new DOMException(DOMException.INVALID_CHARACTER_ERR, "Prefix '" + prefix + "' in XML 1.0 contains invalid characters");
×
217
        } else if(getOwnerDocument().getXmlVersion().equals("1.1") && !XML11Char.isXML11ValidNCName(prefix)) {
×
218
            throw new DOMException(DOMException.INVALID_CHARACTER_ERR, "Prefix '" + prefix + "' in XML 1.1 contains invalid characters");
×
219
        } else if(getNamespaceURI() == null) {
×
220
            throw new DOMException(DOMException.NAMESPACE_ERR, "Cannot set prefix when namespace is null");
×
221
        } else if(prefix.equals(XMLConstants.XML_NS_PREFIX) && !getNamespaceURI().equals(XMLConstants.XML_NS_URI)) {
×
222
            throw new DOMException(DOMException.NAMESPACE_ERR, "Prefix '" + XMLConstants.XML_NS_PREFIX + "' is invalid for namespace '" + getNamespaceURI() + "'");
×
223
        } else if(getNodeType() == Node.ATTRIBUTE_NODE && prefix.equals(XMLConstants.XMLNS_ATTRIBUTE) && !getNamespaceURI().equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) {
×
224
            throw new DOMException(DOMException.NAMESPACE_ERR, "Prefix '" + XMLConstants.XMLNS_ATTRIBUTE + "' is invalid for namespace '" + getNamespaceURI() + "'");
×
225
        } else if(getNodeType() == Node.ELEMENT_NODE || getNodeType() == Node.ATTRIBUTE_NODE) {
×
226
            final QName qname = getQName();
×
227
            setQName(new QName(qname.getLocalPart(), qname.getNamespaceURI(), prefix, qname.getNameType()));
×
228
        }
229
    }
×
230

231
    @Override
232
    public NodeId getNodeId() {
233
        expand();
1✔
234
        return document.nodeId[nodeNumber];
1✔
235
    }
236

237
    // TODO(AR) see if we can get rid of expansion now we have org.exist.dom.memtree.reference.* classes
238
    public void expand() throws DOMException {
239
        document.expand();
1✔
240
    }
1✔
241

242
    public void deepCopy() throws DOMException {
243
        final DocumentImpl newDoc = document.expandRefs(this);
1✔
244
        if(newDoc != document) {
1!
245
            // we received a new document
246
            this.nodeNumber = 1;
×
247
            this.document = newDoc;
×
248
        }
249
    }
1✔
250

251
    @Override
252
    public String getNodeValue() throws DOMException {
253
        return null;
×
254
    }
255

256
    @Override
257
    public void setNodeValue(final String nodeValue) throws DOMException {
258
        throw unsupported();
×
259
    }
260

261
    @Override
262
    public short getNodeType() {
263
        //Workaround for fn:string-length(fn:node-name(document {""}))
264
        if(this.document == null) {
1✔
265
            return Node.DOCUMENT_NODE;
1✔
266
        }
267
        return document.nodeKind[nodeNumber];
1✔
268
    }
269

270
    @Override
271
    public Node getParentNode() {
272
        int next = document.next[nodeNumber];
1✔
273
        while (next > nodeNumber) {
1✔
274
            next = document.next[next];
1✔
275
        }
276
        if (next < 0) {
1!
277
            return null;
×
278
        }
279
        final NodeImpl parent = document.getNode(next);
1✔
280
        if (parent.getNodeType() == DOCUMENT_NODE && !((DocumentImpl) parent).isExplicitlyCreated()) {
1✔
281
            /*
282
                All nodes in the MemTree will return an Owner document due to how the MemTree is implemented,
283
                however the explicitlyCreated flag tells us whether there "really" was a Document Node or not.
284
                See https://github.com/eXist-db/exist/issues/1463
285
             */
286
            return null;
1✔
287
        } else {
288
            return parent;
1✔
289
        }
290
    }
291

292
    public Node selectParentNode() {
293
        // as getParentNode() but doesn't return the document itself
294
        if(nodeNumber == 0) {
1✔
295
            return null;
1✔
296
        }
297
        int next = document.next[nodeNumber];
1✔
298
        while(next > nodeNumber) {
1✔
299
            next = document.next[next];
1✔
300
        }
301
        if(next < 0) { //Is this even possible ?
1!
302
            return null;
×
303
        }
304
        if(next == 0) {
1✔
305
            return this.document.explicitlyCreated ? this.document : null;
1✔
306
        }
307
        return document.getNode(next);
1✔
308
    }
309

310
    @Override
311
    public void addContextNode(final int contextId, final NodeValue node) {
312
        throw unsupported();
×
313
    }
314

315
    @Override
316
    public boolean equals(final Object other) {
317
        if(!(other instanceof NodeImpl o)) {
1!
318
            return false;
×
319
        }
320
        return document == o.document && nodeNumber == o.nodeNumber &&
1✔
321
            getNodeType() == o.getNodeType();
1!
322
    }
323

324
    @Override
325
    public boolean equals(final NodeValue other) throws XPathException {
326
        if(other.getImplementationType() != NodeValue.IN_MEMORY_NODE) {
1!
327
            return false;
×
328
        }
329
        final NodeImpl o = (NodeImpl) other;
1✔
330
        return document == o.document && nodeNumber == o.nodeNumber &&
1!
331
            getNodeType() == o.getNodeType();
1!
332
    }
333

334
    @Override
335
    public boolean after(final NodeValue other, final boolean isFollowing) throws XPathException {
336
        if(other.getImplementationType() != NodeValue.IN_MEMORY_NODE) {
×
337
            throw new XPathException(getExpression(), "cannot compare persistent node with in-memory node");
×
338
        }
339
        return nodeNumber > ((NodeImpl) other).nodeNumber;
×
340
    }
341

342
    @Override
343
    public boolean before(final NodeValue other, final boolean isPreceding) throws XPathException {
344
        if(other.getImplementationType() != NodeValue.IN_MEMORY_NODE) {
×
345
            throw new XPathException(getExpression(), "cannot compare persistent node with in-memory node");
×
346
        }
347
        return nodeNumber < ((NodeImpl)other).nodeNumber;
×
348
    }
349

350
    @Override
351
    public int compareTo(final NodeImpl other) {
352
        if(other.document == document) {
1✔
353
            if(nodeNumber == other.nodeNumber && getNodeType() == other.getNodeType()) {
1!
354
                return Constants.EQUAL;
1✔
355
            } else if(nodeNumber < other.nodeNumber) {
1✔
356
                return Constants.INFERIOR;
1✔
357
            } else {
358
                return Constants.SUPERIOR;
1✔
359
            }
360
        } else if(document.docId < other.document.docId) {
1✔
361
            return Constants.INFERIOR;
1✔
362
        } else {
363
            return Constants.SUPERIOR;
1✔
364
        }
365
    }
366

367
    @Override
368
    public Sequence tail() throws XPathException {
369
        return Sequence.EMPTY_SEQUENCE;
×
370
    }
371

372
    @Override
373
    public NodeList getChildNodes() {
374
        return new NodeListImpl();
1✔
375
    }
376

377
    @Override
378
    public Node getFirstChild() {
379
        return null;
×
380
    }
381

382
    @Override
383
    public Node getLastChild() {
384
        return null;
×
385
    }
386

387
    @Override
388
    public Node getPreviousSibling() {
389
        if(nodeNumber == 0) {
1!
390
            return null;
×
391
        }
392
        final int parent = document.getParentNodeFor(nodeNumber);
1✔
393
        int nextNode = document.getFirstChildFor(parent);
1✔
394
        while((nextNode >= parent) && (nextNode < nodeNumber)) {
1!
395
            final int following = document.next[nextNode];
1✔
396
            if(following == nodeNumber) {
1✔
397
                return document.getNode(nextNode);
1✔
398
            }
399
            nextNode = following;
1✔
400
        }
401
        return null;
1✔
402
    }
403

404
    @Override
405
    public Node getNextSibling() {
406
        final int nextNr = document.next[nodeNumber];
1✔
407
        return nextNr < nodeNumber ? null : document.getNode(nextNr);
1✔
408
    }
409

410
    @Override
411
    public NamedNodeMap getAttributes() {
412
        return null;
1✔
413
    }
414

415
    /**
416
     * Get a list of attributes.
417
     *
418
     * @return the attribute list, or null if there are no attributes.
419
     */
420
    public @Nullable AttrList getAttrList() {
421
        return null;
×
422
    }
423

424
    @Override
425
    public DocumentImpl getOwnerDocument() {
426
        return document;
1✔
427
    }
428

429
    @Override
430
    public Node insertBefore(final Node newChild, final Node refChild) throws DOMException {
431
        throw unsupported();
×
432
    }
433

434
    @Override
435
    public Node replaceChild(final Node newChild, final Node oldChild) throws DOMException {
436
        throw unsupported();
×
437
    }
438

439
    @Override
440
    public Node removeChild(final Node oldChild) throws DOMException {
441
        throw unsupported();
×
442
    }
443

444
    @Override
445
    public Node appendChild(final Node newChild) throws DOMException {
446
        if((newChild.getNodeType() == Node.DOCUMENT_NODE && newChild != document) || newChild.getOwnerDocument() != document) {
×
447
            throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, "Owning document IDs do not match");
×
448
        }
449

450
        throw unsupported();
×
451
    }
452

453
    @Override
454
    public boolean hasChildNodes() {
455
        return false;
×
456
    }
457

458
    @Override
459
    public Node cloneNode(final boolean deep) {
460
        throw unsupported();
×
461
    }
462

463
    @Override
464
    public void normalize() {
465
        // TODO(AR) do we need to implement something here? or is the tree already normalized?
466
        throw unsupported();
×
467
    }
468

469
    @Override
470
    public boolean isSupported(final String feature, final String version) {
471
        throw unsupported();
×
472
    }
473

474
    @Override
475
    public boolean hasAttributes() {
476
        return false;
×
477
    }
478

479
    @Override
480
    public int getType() {
481
        //Workaround for fn:string-length(fn:node-name(document {""}))
482
        if(this.document == null) {
1✔
483
            return Type.DOCUMENT;
1✔
484
        }
485
        return switch (getNodeType()) {
1!
486
            case Node.DOCUMENT_NODE -> Type.DOCUMENT;
1✔
487
            case Node.COMMENT_NODE -> Type.COMMENT;
1✔
488
            case Node.PROCESSING_INSTRUCTION_NODE -> Type.PROCESSING_INSTRUCTION;
1✔
489
            case Node.ELEMENT_NODE -> Type.ELEMENT;
1✔
490
            case Node.ATTRIBUTE_NODE -> Type.ATTRIBUTE;
×
491
            case Node.TEXT_NODE -> Type.TEXT;
1✔
492
            case Node.CDATA_SECTION_NODE -> Type.CDATA_SECTION;
1✔
493
            default -> Type.NODE;
×
494
        };
495
    }
496

497
    @Override
498
    public String getStringValue() {
499
        final int level = document.treeLevel[nodeNumber];
1✔
500
        int next = nodeNumber + 1;
1✔
501
        int startOffset = 0;
1✔
502
        int len = -1;
1✔
503

504
        while(next < document.size && document.treeLevel[next] > level) {
1✔
505
            if(
506
                (document.nodeKind[next] == Node.TEXT_NODE)
1✔
507
                    || (document.nodeKind[next] == Node.CDATA_SECTION_NODE)
1✔
508
                    || (document.nodeKind[next] == Node.PROCESSING_INSTRUCTION_NODE)
1!
509
                ) {
510
                if(len < 0) {
1!
511
                    startOffset = document.alpha[next];
1✔
512
                    len = document.alphaLen[next];
1✔
513
                } else {
1✔
514
                    len += document.alphaLen[next];
×
515
                }
516
            } else {
×
517
                return getStringValueSlow();
1✔
518
            }
519
            ++next;
1✔
520
        }
521
        return len < 0 ? "" : new String(document.characters, startOffset, len);
1✔
522
    }
523

524
    private String getStringValueSlow() {
525
        final int level = document.treeLevel[nodeNumber];
1✔
526
        StringBuilder buf = null;
1✔
527
        int next = nodeNumber + 1;
1✔
528

529
        while(next < document.size && document.treeLevel[next] > level) {
1✔
530
            switch(document.nodeKind[next]) {
1!
531
                case Node.TEXT_NODE:
532
                case Node.CDATA_SECTION_NODE:
533
                case Node.PROCESSING_INSTRUCTION_NODE: {
534
                    if(buf == null) {
1✔
535
                        buf = new StringBuilder();
1✔
536
                    }
537
                    buf.append(document.characters, document.alpha[next], document.alphaLen[next]);
1✔
538
                    break;
1✔
539
                }
540
                case REFERENCE_NODE: {
541
                    if(buf == null) {
×
542
                        buf = new StringBuilder();
×
543
                    }
544
                    buf.append(document.references[document.alpha[next]].getStringValue());
×
545
                    break;
546
                }
547
            }
548
            ++next;
1✔
549
        }
550
        return ((buf == null) ? "" : buf.toString());
1✔
551
    }
552

553
    @Override
554
    public Sequence toSequence() {
555
        return this;
1✔
556
    }
557

558
    @Override
559
    public AtomicValue convertTo(final int requiredType) throws XPathException {
560
        return UntypedAtomicValue.convertTo(null, getStringValue(), requiredType, null);
1✔
561
    }
562

563
    @Override
564
    public AtomicValue atomize() throws XPathException {
565
        return new UntypedAtomicValue(getStringValue());
1✔
566
    }
567

568
    @Override
569
    public boolean isEmpty() {
570
        return false;
1✔
571
    }
572

573
    @Override
574
    public boolean hasOne() {
575
        return true;
1✔
576
    }
577

578
    @Override
579
    public boolean hasMany() {
580
        return false;
1✔
581
    }
582

583
    @Override
584
    public void add(final Item item) throws XPathException {
585
        throw unsupported();
×
586
    }
587

588
    @Override
589
    public void addAll(final Sequence other) throws XPathException {
590
        throw unsupported();
×
591
    }
592

593
    @Override
594
    public int getItemType() {
595
        return Type.NODE;
×
596
    }
597

598
    @Override
599
    public SequenceIterator iterate() {
600
        return new SingleNodeIterator(this);
1✔
601
    }
602

603
    @Override
604
    public SequenceIterator unorderedIterator() {
605
        return new SingleNodeIterator(this);
1✔
606
    }
607

608
    @Override
609
    public long getItemCountLong() {
610
        return 1;
1✔
611
    }
612

613
    @Override
614
    public Cardinality getCardinality() {
615
        return Cardinality.EXACTLY_ONE;
×
616
    }
617

618
    @Override
619
    public Item itemAt(final int pos) {
620
        return pos == 0 ? this : null;
1!
621
    }
622

623
    @Override
624
    public boolean effectiveBooleanValue() throws XPathException {
625
        //A node evaluates to true()
626
        return true;
1✔
627
    }
628

629
    @Override
630
    public NodeSet toNodeSet() throws XPathException {
631
        final ValueSequence seq = new ValueSequence();
×
632
        seq.add(this);
×
633
        return seq.toNodeSet();
×
634
    }
635

636
    @Override
637
    public MemoryNodeSet toMemNodeSet() throws XPathException {
638
        return new ValueSequence(this).toMemNodeSet();
1✔
639
    }
640

641
    @Override
642
    public void toSAX(final DBBroker broker, final ContentHandler handler, final Properties properties)
643
            throws SAXException {
644
        final Serializer serializer = broker.borrowSerializer();
1✔
645
        try {
646
            serializer.setProperty(Serializer.GENERATE_DOC_EVENTS, "false");
1✔
647

648
            if (properties != null) {
1✔
649
                serializer.setProperties(properties);
1✔
650
            }
651

652
            if (handler instanceof LexicalHandler) {
1!
653
                serializer.setSAXHandlers(handler, (LexicalHandler) handler);
1✔
654
            } else {
1✔
655
                serializer.setSAXHandlers(handler, null);
×
656
            }
657

658
            serializer.toSAX(this);
1✔
659
        } finally {
1✔
660
            broker.returnSerializer(serializer);
1✔
661
        }
662
    }
1✔
663

664
    @Override
665
    public void copyTo(final DBBroker broker, final DocumentBuilderReceiver receiver) throws SAXException {
666
        //Null test for document nodes
667
        if(document != null) {
1✔
668
            document.copyTo(this, receiver);
1✔
669
        }
670
    }
1✔
671

672
    public void streamTo(final Serializer serializer, final Receiver receiver) throws SAXException {
673
        //Null test for document nodes
674
        if(document != null) {
1✔
675
            document.streamTo(serializer, this, receiver);
1✔
676
        }
677
    }
1✔
678

679
    @Override
680
    public int conversionPreference(final Class<?> javaClass) {
681
        final int preference;
682
        if(javaClass.isAssignableFrom(NodeImpl.class)) {
×
683
            preference = 0;
×
684
        } else if(javaClass.isAssignableFrom(Node.class)) {
×
685
            preference = 1;
×
686
        } else if((javaClass == String.class) || (javaClass == CharSequence.class)) {
×
687
            preference = 2;
×
688
        } else if((javaClass == Character.class) || (javaClass == char.class)) {
×
689
            preference = 2;
×
690
        } else if((javaClass == Double.class) || (javaClass == double.class)) {
×
691
            preference = 10;
×
692
        } else if((javaClass == Float.class) || (javaClass == float.class)) {
×
693
            preference = 11;
×
694
        } else if((javaClass == Long.class) || (javaClass == long.class)) {
×
695
            preference = 12;
×
696
        } else if((javaClass == Integer.class) || (javaClass == int.class)) {
×
697
            preference = 13;
×
698
        } else if((javaClass == Short.class) || (javaClass == short.class)) {
×
699
            preference = 14;
×
700
        } else if((javaClass == Byte.class) || (javaClass == byte.class)) {
×
701
            preference = 15;
×
702
        } else if((javaClass == Boolean.class) || (javaClass == boolean.class)) {
×
703
            preference = 16;
×
704
        } else if(javaClass == Object.class) {
×
705
            preference = 20;
×
706
        } else {
×
707
            preference = Integer.MAX_VALUE;
×
708
        }
709
        return preference;
×
710
    }
711

712
    @Override
713
    public <T> T toJavaObject(final Class<T> target) throws XPathException {
714
        if(target.isAssignableFrom(NodeImpl.class) || target.isAssignableFrom(Node.class) || target == Object.class) {
1!
715
            return (T) this;
1✔
716
        } else {
717
            final StringValue v = new StringValue(getStringValue());
×
718
            return v.toJavaObject(target);
×
719
        }
720
    }
721

722
    @Override
723
    public void setSelfAsContext(final int contextId) {
724
        throw unsupported();
×
725
    }
726

727
    @Override
728
    public boolean isCached() {
729
        // always return false
730
        return false;
×
731
    }
732

733
    @Override
734
    public void setIsCached(final boolean cached) {
735
        throw unsupported();
×
736
    }
737

738
    @Override
739
    public void removeDuplicates() {
740
    }
1✔
741

742
    @Override
743
    public String getBaseURI() {
744
        return null;
1✔
745
    }
746

747
    @Override
748
    public boolean containsReference(final Item item) {
749
        return this == item;
×
750
    }
751

752
    @Override
753
    public boolean contains(final Item item) {
754
        return equals(item);
×
755
    }
756

757
    @Override
758
    public void destroy(final XQueryContext context, @Nullable final Sequence contextSequence) {
759
    }
1✔
760

761

762
    public abstract void selectAttributes(final NodeTest test, final Sequence result) throws XPathException;
763

764
    public abstract void selectDescendantAttributes(final NodeTest test, final Sequence result) throws XPathException;
765

766
    public abstract void selectChildren(final NodeTest test, final Sequence result) throws XPathException;
767

768
    public void selectDescendants(final boolean includeSelf, final NodeTest test, final Sequence result)
769
        throws XPathException {
770
        if(includeSelf && test.matches(this)) {
×
771
            result.add(this);
×
772
        }
773
    }
×
774

775
    public void selectAncestors(final boolean includeSelf, final NodeTest test, final Sequence result)
776
        throws XPathException {
777
        if(nodeNumber < 1) {
1✔
778
            return;
1✔
779
        }
780
        if(includeSelf) {
1✔
781
            final NodeImpl n = document.getNode(nodeNumber);
1✔
782
            if(test.matches(n)) {
1✔
783
                result.add(n);
1✔
784
            }
785
        }
786
        int nextNode = document.getParentNodeFor(nodeNumber);
1✔
787
        while(nextNode > 0) {
1✔
788
            final NodeImpl n = document.getNode(nextNode);
1✔
789
            if(test.matches(n)) {
1✔
790
                result.add(n);
1✔
791
            }
792
            nextNode = document.getParentNodeFor(nextNode);
1✔
793
        }
794
    }
1✔
795

796
    public void selectPrecedingSiblings(final NodeTest test, final Sequence result)
797
        throws XPathException {
798
        final int parent = document.getParentNodeFor(nodeNumber);
1✔
799
        int nextNode = document.getFirstChildFor(parent);
1✔
800
        while((nextNode >= parent) && (nextNode < nodeNumber)) {
1!
801
            final NodeImpl n = document.getNode(nextNode);
1✔
802
            if(test.matches(n)) {
1✔
803
                result.add(n);
1✔
804
            }
805
            nextNode = document.next[nextNode];
1✔
806
        }
807
    }
1✔
808

809
    public void selectPreceding(final NodeTest test, final Sequence result, final int position)
810
        throws XPathException {
811
        final NodeId myNodeId = getNodeId();
1✔
812
        int count = 0;
1✔
813

814
        for(int i = nodeNumber - 1; i > 0; i--) {
1✔
815
            final NodeImpl n = document.getNode(i);
1✔
816
            if(!myNodeId.isDescendantOf(n.getNodeId()) && test.matches(n)) {
1✔
817
                if((position < 0) || (++count == position)) {
1✔
818
                    result.add(n);
1✔
819
                }
820
                if(count == position) {
1✔
821
                    break;
1✔
822
                }
823
            }
824
        }
825
    }
1✔
826

827
    public void selectFollowingSiblings(final NodeTest test, final Sequence result)
828
        throws XPathException {
829
        final int parent = document.getParentNodeFor(nodeNumber);
1✔
830
        int nextNode = document.getFirstChildFor(parent);
1✔
831
        while(nextNode > parent) {
1✔
832
            final NodeImpl n = document.getNode(nextNode);
1✔
833
            if((nextNode > nodeNumber) && test.matches(n)) {
1✔
834
                result.add(n);
1✔
835
            }
836
            nextNode = document.next[nextNode];
1✔
837
        }
838
    }
1✔
839

840
    public void selectFollowing(final NodeTest test, final Sequence result, final int position)
841
        throws XPathException {
842
        final int parent = document.getParentNodeFor(nodeNumber);
1✔
843
        if(parent == 0) {
1✔
844
            // parent is the document node
845
            if(getNodeType() == Node.ELEMENT_NODE) {
1!
846
                return;
1✔
847
            }
848
            NodeImpl next = (NodeImpl) getNextSibling();
×
849
            while(next != null) {
×
850
                if(test.matches(next)) {
×
851
                    next.selectDescendants(true, test, result);
×
852
                }
853
                if(next.getNodeType() == Node.ELEMENT_NODE) {
×
854
                    break;
×
855
                }
856
                next = (NodeImpl) next.getNextSibling();
×
857
            }
858
        } else {
×
859
            final NodeId myNodeId = getNodeId();
1✔
860
            int count = 0;
1✔
861
            int nextNode = nodeNumber + 1;
1✔
862
            while(nextNode < document.size) {
1✔
863
                final NodeImpl n = document.getNode(nextNode);
1✔
864
                if(!n.getNodeId().isDescendantOf(myNodeId) && test.matches(n)) {
1✔
865
                    if((position < 0) || (++count == position)) {
1✔
866
                        result.add(n);
1✔
867
                    }
868
                    if(count == position) {
1✔
869
                        break;
1✔
870
                    }
871
                }
872
                nextNode++;
1✔
873
            }
874
        }
875
    }
1✔
876

877
    public boolean matchAttributes(final NodeTest test) {
878
        // do nothing
879
        return false;
×
880
    }
881

882
    public boolean matchDescendantAttributes(final NodeTest test) throws XPathException {
883
        // do nothing
884
        return false;
×
885
    }
886

887
    public boolean matchChildren(final NodeTest test) throws XPathException {
888
        return false;
×
889
    }
890

891
    public boolean matchDescendants(final boolean includeSelf, final NodeTest test) throws XPathException {
892
        return includeSelf && test.matches(this);
×
893
    }
894

895
    @Override
896
    public short compareDocumentPosition(final Node other) throws DOMException {
897
        throw unsupported();
×
898
    }
899

900
    @Override
901
    public String getTextContent() throws DOMException {
902
        throw unsupported();
×
903
    }
904

905
    @Override
906
    public void setTextContent(final String textContent) throws DOMException {
907
        throw unsupported();
×
908
    }
909

910
    @Override
911
    public boolean isSameNode(final Node other) {
912
        throw unsupported();
×
913
    }
914

915
    @Override
916
    public String lookupPrefix(final String namespaceURI) {
917
        throw unsupported();
×
918
    }
919

920
    @Override
921
    public boolean isDefaultNamespace(final String namespaceURI) {
922
        throw unsupported();
×
923
    }
924

925
    @Override
926
    public String lookupNamespaceURI(final String prefix) {
927
        throw unsupported();
×
928
    }
929

930
    @Override
931
    public boolean isEqualNode(final Node arg) {
932
        throw unsupported();
×
933
    }
934

935
    @Override
936
    public Object getFeature(final String feature, final String version) {
937
        throw unsupported();
×
938
    }
939

940
    @Override
941
    public Object setUserData(final String key, final Object data, final UserDataHandler handler) {
942
        throw unsupported();
×
943
    }
944

945
    @Override
946
    public Object getUserData(final String key) {
947
        throw unsupported();
×
948
    }
949

950
    @Override
951
    public boolean isPersistentSet() {
952
        return false;
1✔
953
    }
954

955
    @Override
956
    public void nodeMoved(final NodeId oldNodeId, final NodeHandle newNode) {
957
    }
×
958

959
    @Override
960
    public void clearContext(final int contextId) {
961
    }
1✔
962

963
    @Override
964
    public int getState() {
965
        return 0;
1✔
966
    }
967

968
    @Override
969
    public boolean isCacheable() {
970
        return true;
1✔
971
    }
972

973
    @Override
974
    public boolean hasChanged(final int previousState) {
975
        return false;
×
976
    }
977

978

979
    protected DOMException unsupported() {
980
        return new DOMException(DOMException.NOT_SUPPORTED_ERR, "not implemented on class: " + getClass().getName());
×
981
    }
982

983
    private final static class SingleNodeIterator implements SequenceIterator {
984
        private NodeImpl node;
985

986
        public SingleNodeIterator(final NodeImpl node) {
1✔
987
            this.node = node;
1✔
988
        }
1✔
989

990
        @Override
991
        public boolean hasNext() {
992
            return node != null;
1✔
993
        }
994

995
        @Override
996
        public Item nextItem() {
997
            final NodeImpl next = node;
1✔
998
            node = null;
1✔
999
            return next;
1✔
1000
        }
1001

1002
        @Override
1003
        public long skippable() {
1004
            if (node != null) {
1✔
1005
                return 1;
1✔
1006
            }
1007
            return 0;
1✔
1008
        }
1009

1010
        @Override
1011
        public long skip(final long n) {
1012
            final long skip = Math.min(n, node != null ? 1 : 0);
1✔
1013
            if (skip == 1) {
1✔
1014
                node = null;
1✔
1015
            }
1016
            return skip;
1✔
1017
        }
1018
    }
1019
}
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