• 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

50.23
/exist-core/src/main/java/org/exist/dom/memtree/ElementImpl.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.exist.Namespaces;
52
import org.exist.dom.NamedNodeMapImpl;
53
import org.exist.dom.NodeListImpl;
54
import org.exist.dom.QName;
55
import org.exist.dom.QName.IllegalQNameException;
56
import org.exist.storage.ElementValue;
57
import org.exist.util.serializer.AttrList;
58
import org.exist.xmldb.XmldbURI;
59
import org.exist.xquery.Expression;
60
import org.exist.xquery.NodeTest;
61
import org.exist.xquery.XPathException;
62
import org.exist.xquery.value.Sequence;
63
import org.exist.xquery.value.Type;
64
import org.exist.xquery.value.ValueSequence;
65
import org.w3c.dom.*;
66

67
import javax.xml.XMLConstants;
68
import java.util.HashMap;
69
import java.util.HashSet;
70
import java.util.Map;
71
import java.util.Set;
72
import java.util.function.Function;
73

74
import static org.exist.dom.QName.Validity.ILLEGAL_FORMAT;
75

76

77
public class ElementImpl extends NodeImpl implements Element {
78

79
    public ElementImpl(final DocumentImpl doc, final int nodeNumber) {
80
        this(null, doc, nodeNumber);
×
81
    }
×
82

83
    public ElementImpl(final Expression expression, final DocumentImpl doc, final int nodeNumber) {
84
        super(expression, doc, nodeNumber);
1✔
85
    }
1✔
86

87
    @Override
88
    public String getTagName() {
89
        return getNodeName();
1✔
90
    }
91

92
    @Override
93
    public boolean hasChildNodes() {
94
        return (nodeNumber + 1) < document.size && document.treeLevel[nodeNumber + 1] > document.treeLevel[nodeNumber];
1✔
95
    }
96

97
    @Override
98
    public Node getFirstChild() {
99
        final short level = document.treeLevel[nodeNumber];
1✔
100
        final int nextNode = nodeNumber + 1;
1✔
101
        if(nextNode < document.size && document.treeLevel[nextNode] > level) {
1✔
102
            return document.getNode(nextNode);
1✔
103
        }
104
        return null;
1✔
105
    }
106

107
    @Override
108
    public NodeList getChildNodes() {
109
        final NodeListImpl nl = new NodeListImpl(1);  // nil elements are rare, so we use 1 here
1✔
110
        int nextNode = document.getFirstChildFor(nodeNumber);
1✔
111
        while(nextNode > nodeNumber) {
1✔
112
            final Node n = document.getNode(nextNode);
1✔
113
            if(n.getNodeType() != Node.ATTRIBUTE_NODE) {
1!
114
                nl.add(n);
1✔
115
            }
116
            nextNode = document.next[nextNode];
1✔
117
        }
118
        return nl;
1✔
119
    }
120

121
    private int getChildCount() {
122
        return document.getChildCountFor(nodeNumber);
1✔
123
    }
124

125
    @Override
126
    public boolean hasAttributes() {
127
        return document.alpha[nodeNumber] > -1 || document.alphaLen[nodeNumber] > -1;
×
128
    }
129

130
    @Override
131
    public String getAttribute(final String name) {
132
        int attr = document.alpha[nodeNumber];
1✔
133

134
        if(-1 < attr) {
1✔
135
            while (attr < document.nextAttr && document.attrParent[attr] == nodeNumber) {
1✔
136
                final QName attrQName = document.attrName[attr];
1✔
137
                if (attrQName.getStringValue().equals(name)) {
1✔
138
                    return document.attrValue[attr];
1✔
139
                }
140
                ++attr;
1✔
141
            }
142
        }
143

144
        if (name.startsWith(XMLConstants.XMLNS_ATTRIBUTE + ":")) {
1!
145
            int ns = document.alphaLen[nodeNumber];
×
146
            if (-1 < ns) {
×
147
                while (ns < document.nextNamespace && document.namespaceParent[ns] == nodeNumber) {
×
148
                    final QName nsQName = document.namespaceCode[ns];
×
149
                    if (nsQName.getStringValue().equals(name)) {
×
150
                        return nsQName.getNamespaceURI();
×
151
                    }
152
                    ++ns;
×
153
                }
154
            }
155
        }
156

157
        return "";
1✔
158
    }
159

160
    @Override
161
    public void setAttribute(final String name, final String value) throws DOMException {
162
        final QName qname;
163
        try {
164
            if(document.context != null) {
×
165
                qname = QName.parse(document.context, name);
×
166
            } else {
×
167
                qname = new QName(name);
×
168
            }
169
        } catch (final IllegalQNameException e) {
×
170
            throw new DOMException(DOMException.INVALID_CHARACTER_ERR, e.getMessage());
×
171
        }
172

173
        // check the QName is valid for use
174
        if(qname.isValid(false) != QName.Validity.VALID.val) {
×
175
            throw new DOMException(DOMException.INVALID_CHARACTER_ERR, "name is invalid");
×
176
        }
177

178
        setAttribute(qname, value, qn -> getAttributeNode(qn.getLocalPart()));
×
179
    }
×
180

181
    @Override
182
    public void setAttributeNS(final String namespaceURI, final String qualifiedName, final String value) throws DOMException {
183
        final QName qname;
184
        try {
185
            if(document.context != null) {
×
186
                qname = QName.parse(document.context, qualifiedName, namespaceURI);
×
187
            } else {
×
188
                qname = QName.parse(namespaceURI, qualifiedName);
×
189
            }
190
        } catch (final IllegalQNameException e) {
×
191
            final short errCode;
192
            if(e.getValidity() == ILLEGAL_FORMAT.val || (e.getValidity() & QName.Validity.INVALID_NAMESPACE.val) == QName.Validity.INVALID_NAMESPACE.val) {
×
193
                errCode = DOMException.NAMESPACE_ERR;
×
194
            } else {
×
195
                errCode = DOMException.INVALID_CHARACTER_ERR;
×
196
            }
197
            throw new DOMException(errCode, "qualified name is invalid");
×
198
        }
199

200
        // check the QName is valid for use
201
        final byte validity = qname.isValid(false);
×
202
        if((validity & QName.Validity.INVALID_LOCAL_PART.val) == QName.Validity.INVALID_LOCAL_PART.val) {
×
203
            throw new DOMException(DOMException.INVALID_CHARACTER_ERR, "qualified name is invalid");
×
204
        } else if((validity & QName.Validity.INVALID_NAMESPACE.val) == QName.Validity.INVALID_NAMESPACE.val) {
×
205
            throw new DOMException(DOMException.NAMESPACE_ERR, "qualified name is invalid");
×
206
        }
207

208
        setAttribute(qname, value, qn -> getAttributeNodeNS(qn.getNamespaceURI(), qn.getLocalPart()));
×
209
    }
×
210

211
    private void setAttribute(final QName name, final String value, final Function<QName, Attr> getFn) {
212
        final Attr existingAttr = getFn.apply(name);
×
213
        if(existingAttr != null) {
×
214

215
            // update an existing attribute
216
            existingAttr.setValue(value);
×
217

218
        } else {
×
219

220
            // create a new attribute
221

222
            final int lastNode = document.getLastNode();
×
223
            document.addAttribute(lastNode, name, value, AttrImpl.ATTR_CDATA_TYPE);
×
224
        }
225
    }
×
226

227
    @Override
228
    public void removeAttribute(final String name) throws DOMException {
229
    }
×
230

231
    @Override
232
    public NamedNodeMap getAttributes() {
233
        final NamedNodeMapImpl map = new NamedNodeMapImpl(document, true);
1✔
234
        int attr = document.alpha[nodeNumber];
1✔
235
        if(-1 < attr) {
1✔
236
            while(attr < document.nextAttr && document.attrParent[attr] == nodeNumber) {
1✔
237
                map.setNamedItem(new AttrImpl(getExpression(), document, attr));
1✔
238
                ++attr;
1✔
239
            }
240
        }
241
        // add namespace declarations attached to this element
242
        int ns = document.alphaLen[nodeNumber];
1✔
243
        if(ns < 0) {
1✔
244
            return (map);
1✔
245
        }
246
        while(ns < document.nextNamespace && document.namespaceParent[ns] == nodeNumber) {
1✔
247
            final NamespaceNode node = new NamespaceNode(getExpression(), document, ns);
1✔
248
            map.setNamedItem(node);
1✔
249
            ++ns;
1✔
250
        }
251
        return map;
1✔
252
    }
253

254
    @Override
255
    public AttrList getAttrList() {
256
        //Create the attribute list
257
        AttrList attrList = null;
1✔
258
        int attr = document.alpha[nodeNumber];
1✔
259
        if (attr > -1) {
1✔
260
            attrList = new AttrList();
1✔
261
            while((attr < document.nextAttr) && (document.attrParent[attr] == nodeNumber)) {
1✔
262
                final QName attrQName = document.attrName[attr];
1✔
263
                attrList.addAttribute(attrQName, document.attrValue[attr]);
1✔
264
                ++attr;
1✔
265
            }
266
        }
267
        return attrList;
1✔
268
    }
269

270
    @Override
271
    public Attr getAttributeNode(final String name) {
272
        int attr = document.alpha[nodeNumber];
1✔
273
        if(-1 < attr) {
1!
274
            while(attr < document.nextAttr && document.attrParent[attr] == nodeNumber) {
1!
275
                final QName attrQName = document.attrName[attr];
1✔
276
                if(attrQName.getStringValue().equals(name)) {
1✔
277
                    return new AttrImpl(getExpression(), document, attr);
1✔
278
                }
279
                ++attr;
1✔
280
            }
281
        }
282
        if(name.startsWith(XMLConstants.XMLNS_ATTRIBUTE + ":")) {
×
283
            int ns = document.alphaLen[nodeNumber];
×
284
            if(-1 < ns) {
×
285
                while(ns < document.nextNamespace && document.namespaceParent[ns] == nodeNumber) {
×
286
                    final QName nsQName = document.namespaceCode[ns];
×
287
                    if(nsQName.getStringValue().equals(name)) {
×
288
                        return new NamespaceNode(getExpression(), document, ns);
×
289
                    }
290
                    ++ns;
×
291
                }
292
            }
293
        }
294
        return null;
×
295
    }
296

297
    @Override
298
    public Attr setAttributeNode(final Attr newAttr) throws DOMException {
299
        return setAttributeNode(newAttr, qname -> getAttributeNode(qname.getLocalPart()));
×
300
    }
301

302
    private Attr setAttributeNode(final Attr newAttr, final Function<QName, Attr> getFn) {
303
        final QName attrName = new QName(newAttr.getLocalName(), newAttr.getNamespaceURI(), newAttr.getPrefix(), ElementValue.ATTRIBUTE);
×
304
        final Attr existingAttr = getFn.apply(attrName);
×
305

306
        if(existingAttr != null) {
×
307
            if(existingAttr.equals(newAttr)) {
×
308
                return newAttr;
×
309
            }
310

311
            // update an existing attribute
312
            existingAttr.setValue(newAttr.getValue());
×
313

314
            return existingAttr;
×
315

316
        } else {
317

318
            // create a new attribute
319

320
            final int lastNode = document.getLastNode();
×
321
            final int attrNodeNum = document.addAttribute(lastNode, attrName, newAttr.getValue(), AttrImpl.ATTR_CDATA_TYPE);
×
322
            return new AttrImpl(getExpression(), document, attrNodeNum);
×
323
        }
324
    }
325

326
    @Override
327
    public Attr removeAttributeNode(final Attr oldAttr) throws DOMException {
328
        return null;
×
329
    }
330

331
    @Override
332
    public void selectAttributes(final NodeTest test, final Sequence result) throws XPathException {
333
        int attr = document.alpha[nodeNumber];
1✔
334
        if(-1 < attr) {
1✔
335
            while(attr < document.nextAttr && document.attrParent[attr] == nodeNumber) {
1✔
336
                final AttrImpl attrib = new AttrImpl(getExpression(), document, attr);
1✔
337
                if(test.matches(attrib)) {
1✔
338
                    result.add(attrib);
1✔
339
                }
340
                ++attr;
1✔
341
            }
342
        }
343
    }
1✔
344

345
    @Override
346
    public void selectDescendantAttributes(final NodeTest test, final Sequence result) throws XPathException {
347
        final int treeLevel = document.treeLevel[nodeNumber];
1✔
348
        int nextNode = nodeNumber;
1✔
349
        NodeImpl n = document.getNode(nextNode);
1✔
350
        n.selectAttributes(test, result);
1✔
351
        while(++nextNode < document.size && document.treeLevel[nextNode] > treeLevel) {
1✔
352
            n = document.getNode(nextNode);
1✔
353
            if(n.getNodeType() == Node.ELEMENT_NODE) {
1✔
354
                n.selectAttributes(test, result);
1✔
355
            }
356
        }
357
    }
1✔
358

359
    @Override
360
    public void selectChildren(final NodeTest test, final Sequence result) throws XPathException {
361
        int nextNode = document.getFirstChildFor(nodeNumber);
1✔
362
        while(nextNode > nodeNumber) {
1✔
363
            final NodeImpl n = document.getNode(nextNode);
1✔
364
            if(test.matches(n)) {
1✔
365
                result.add(n);
1✔
366
            }
367
            nextNode = document.next[nextNode];
1✔
368
        }
369
    }
1✔
370

371
    public NodeImpl getFirstChild(final NodeTest test) throws XPathException {
372
        final ValueSequence seq = new ValueSequence();
×
373
        selectChildren(test, seq);
×
374
        return seq.isEmpty() ? null : seq.get(0);
×
375
    }
376

377
    @Override
378
    public void selectDescendants(final boolean includeSelf, final NodeTest test, final Sequence result)
379
        throws XPathException {
380
        final int treeLevel = document.treeLevel[nodeNumber];
1✔
381
        int nextNode = nodeNumber;
1✔
382

383
        if(includeSelf) {
1✔
384
            final NodeImpl n = document.getNode(nextNode);
1✔
385
            if(test.matches(n)) {
1✔
386
                result.add(n);
1✔
387
            }
388
        }
389

390
        while(++nextNode < document.size && document.treeLevel[nextNode] > treeLevel) {
1✔
391
            final NodeImpl n = document.getNode(nextNode);
1✔
392
            if(test.matches(n)) {
1✔
393
                result.add(n);
1✔
394
            }
395
        }
396
    }
1✔
397

398
    @Override
399
    public NodeList getElementsByTagName(final String name) {
400
        if(name != null && name.equals(QName.WILDCARD)) {
1!
401
            return getElementsByTagName(new QName.WildcardLocalPartQName(XMLConstants.DEFAULT_NS_PREFIX));
×
402
        } else {
403
            final QName qname;
404
            try {
405
                if (document.getContext() != null) {
1✔
406
                    qname = QName.parse(document.context, name);
1✔
407
                } else {
1✔
408
                    qname = new QName(name);
1✔
409
                }
410
            } catch (final IllegalQNameException e) {
1✔
411
                throw new DOMException(DOMException.INVALID_CHARACTER_ERR, e.getMessage());
×
412
            }
413
            return getElementsByTagName(qname);
1✔
414
        }
415
    }
416

417
    @Override
418
    public NodeList getElementsByTagNameNS(final String namespaceURI, final String localName) {
419
        final boolean wildcardNS = namespaceURI != null && namespaceURI.equals(QName.WILDCARD);
×
420
        final boolean wildcardLocalPart = localName != null && localName.equals(QName.WILDCARD);
×
421

422
        if(wildcardNS && wildcardLocalPart) {
×
423
            return getElementsByTagName(QName.WildcardQName.getInstance());
×
424
        } else if(wildcardNS) {
×
425
            return getElementsByTagName(new QName.WildcardNamespaceURIQName(localName));
×
426
        } else if(wildcardLocalPart) {
×
427
            return getElementsByTagName(new QName.WildcardLocalPartQName(namespaceURI));
×
428
        } else {
429
            final QName qname;
430
            if (document.getContext() != null) {
×
431
                try {
432
                    qname = QName.parse(document.context, localName, namespaceURI);
×
433
                } catch (final IllegalQNameException e) {
×
434
                    throw new DOMException(DOMException.INVALID_CHARACTER_ERR, e.getMessage());
×
435
                }
436
            } else {
437
                qname = new QName(localName, namespaceURI);
×
438
            }
439
            return getElementsByTagName(qname);
×
440
        }
441
    }
442

443
    private NodeList getElementsByTagName(final QName qname) {
444
        final NodeListImpl nl = new NodeListImpl();
1✔
445
        int nextNode = nodeNumber;
1✔
446
        final int treeLevel = document.treeLevel[nodeNumber];
1✔
447
        while(++nextNode < document.size && document.treeLevel[nextNode] > treeLevel) {
1✔
448
            if(document.nodeKind[nextNode] == Node.ELEMENT_NODE) {
1✔
449
                final QName qn = document.nodeName[nextNode];
1✔
450
                if(qname.matches(qn)) {
1✔
451
                    nl.add(document.getNode(nextNode));
1✔
452
                }
453
            }
454
        }
455
        return nl;
1✔
456
    }
457

458
    @Override
459
    public String getAttributeNS(final String namespaceURI, final String localName) {
460
        int attr = document.alpha[nodeNumber];
1✔
461

462
        if (-1 < attr) {
1✔
463
            while (attr < document.nextAttr && document.attrParent[attr] == nodeNumber) {
1!
464
                final QName name = document.attrName[attr];
1✔
465
                if (name.getLocalPart().equals(localName) && name.getNamespaceURI().equals(namespaceURI)) {
1!
466
                    return document.attrValue[attr];
1✔
467
                }
468
                ++attr;
1✔
469
            }
470
        }
471

472
        if (Namespaces.XMLNS_NS.equals(namespaceURI)) {
1!
473
            int ns = document.alphaLen[nodeNumber];
×
474
            if (-1 < ns) {
×
475
                while (ns < document.nextNamespace && document.namespaceParent[ns] == nodeNumber) {
×
476
                    final QName nsQName = document.namespaceCode[ns];
×
477
                    if (nsQName.getLocalPart().equals(localName)) {
×
478
                        return nsQName.getNamespaceURI();
×
479
                    }
480
                    ++ns;
×
481
                }
482
            }
483
        }
484

485
        return "";
1✔
486
    }
487

488
    @Override
489
    public void removeAttributeNS(final String namespaceURI, final String localName) throws DOMException {
490
    }
×
491

492
    @Override
493
    public Attr getAttributeNodeNS(final String namespaceURI, final String localName) {
494
        int attr = document.alpha[nodeNumber];
×
495
        if(-1 < attr) {
×
496
            while((attr < document.nextAttr) && (document.attrParent[attr] == nodeNumber)) {
×
497
                final QName name = document.attrName[attr];
×
498
                if(name.getLocalPart().equals(localName) && name.getNamespaceURI().equals(namespaceURI)) {
×
499
                    return (new AttrImpl(getExpression(), document, attr));
×
500
                }
501
                ++attr;
×
502
            }
503
        }
504
        if(Namespaces.XMLNS_NS.equals(namespaceURI)) {
×
505
            int ns = document.alphaLen[nodeNumber];
×
506
            if(-1 < ns) {
×
507
                while((ns < document.nextNamespace) && (document.namespaceParent[ns] == nodeNumber)) {
×
508
                    final QName nsQName = document.namespaceCode[ns];
×
509
                    if(nsQName.getLocalPart().equals(localName)) {
×
510
                        return (new NamespaceNode(getExpression(), document, ns));
×
511
                    }
512
                    ++ns;
×
513
                }
514
            }
515
        }
516
        return null;
×
517
    }
518

519
    @Override
520
    public Attr setAttributeNodeNS(final Attr newAttr) throws DOMException {
521
        return setAttributeNode(newAttr, qname -> getAttributeNodeNS(qname.getNamespaceURI(), qname.getLocalPart()));
×
522
    }
523

524
    @Override
525
    public boolean hasAttribute(final String name) {
526
        int attr = document.alpha[nodeNumber];
1✔
527

528
        if (-1 < attr) {
1!
529
            while (attr < document.nextAttr && document.attrParent[attr] == nodeNumber) {
1✔
530
                final QName attrQName = document.attrName[attr];
1✔
531
                if (attrQName.getStringValue().equals(name)) {
1✔
532
                    return true;
1✔
533
                }
534
                ++attr;
1✔
535
            }
536
        }
537

538
        if (name.startsWith(XMLConstants.XMLNS_ATTRIBUTE + ":")) {
1!
539
            int ns = document.alphaLen[nodeNumber];
×
540
            if (-1 < ns) {
×
541
                while (ns < document.nextNamespace && document.namespaceParent[ns] == nodeNumber) {
×
542
                    final QName nsQName = document.namespaceCode[ns];
×
543
                    if (nsQName.getStringValue().equals(name)) {
×
544
                        return true;
×
545
                    }
546
                    ++ns;
×
547
                }
548
            }
549
        }
550

551
        return false;
1✔
552
    }
553

554
    @Override
555
    public boolean hasAttributeNS(final String namespaceURI, final String localName) {
556
        return getAttributeNS(namespaceURI, localName) != null;
×
557
    }
558

559
    /**
560
     * The method <code>getPrefixes.</code>
561
     *
562
     * @return a <code>Set</code> value
563
     */
564
    public Set<String> getPrefixes() {
565
        final Set<String> set = new HashSet<>();
×
566
        int ns = document.alphaLen[nodeNumber];
×
567
        if(-1 < ns) {
×
568
            while(ns < document.nextNamespace && document.namespaceParent[ns] == nodeNumber) {
×
569
                final QName nsQName = document.namespaceCode[ns];
×
570
                set.add(nsQName.getStringValue());
×
571
                ++ns;
×
572
            }
573
        }
574
        return set;
×
575
    }
576

577
    /**
578
     * The method <code>declaresNamespacePrefixes.</code>
579
     *
580
     * @return a <code>boolean</code> value
581
     */
582
    public boolean declaresNamespacePrefixes() {
583
        return document.getNamespacesCountFor(nodeNumber) > 0;
1✔
584
    }
585

586
    /**
587
     * The method <code>getNamespaceMap.</code>
588
     *
589
     * @return a <code>Map</code> value
590
     */
591
    public Map<String, String> getNamespaceMap() {
592
        return getNamespaceMap(new HashMap<>());
1✔
593
    }
594

595
    public Map<String, String> getNamespaceMap(final Map<String, String> map) {
596
        int ns = document.alphaLen[nodeNumber];
1✔
597
        if(-1 < ns) {
1✔
598
            while(ns < document.nextNamespace && document.namespaceParent[ns] == nodeNumber) {
1✔
599
                final QName nsQName = document.namespaceCode[ns];
1✔
600
                map.put(nsQName.getLocalPart(), nsQName.getNamespaceURI());
1✔
601
                ++ns;
1✔
602
            }
603
        }
604

605
        int attr = document.alpha[nodeNumber];
1✔
606
        if(-1 < attr) {
1✔
607
            while(attr < document.nextAttr && document.attrParent[attr] == nodeNumber) {
1✔
608
                final QName qname = document.attrName[attr];
1✔
609
                if(qname.getPrefix() != null && !qname.getPrefix().isEmpty()) {
1!
610
                    map.put(qname.getPrefix(), qname.getNamespaceURI());
×
611
                }
612
                ++attr;
1✔
613
            }
614
        }
615

616
        return map;
1✔
617
    }
618

619
    @Override
620
    public int getItemType() {
621
        return Type.ELEMENT;
1✔
622
    }
623

624
    @Override
625
    public String getBaseURI() {
626
        final XmldbURI baseURI = calculateBaseURI();
1✔
627
        if(baseURI != null) {
1!
628
            return baseURI.toString();
1✔
629
        }
630

631
        return "";//UNDERSTAND: is it ok?
×
632
    }
633

634
    // NOTE(AR) please keep in sync with org.exist.dom.persistent.ElementImpl
635
    private XmldbURI calculateBaseURI() {
636
        XmldbURI baseURI = null;
1✔
637

638
        final String nodeBaseURI = getAttributeNS(Namespaces.XML_NS, "base");
1✔
639
        if (!nodeBaseURI.isEmpty()) {
1✔
640
            baseURI = XmldbURI.create(nodeBaseURI, false);
1✔
641
            if (baseURI.isAbsolute()) {
1✔
642
                return baseURI;
1✔
643
            }
644
        }
645

646
        int parent = -1;
1✔
647
        final int test = document.getParentNodeFor(nodeNumber);
1✔
648
        if (document.nodeKind[test] != Node.DOCUMENT_NODE) {
1✔
649
            parent = test;
1✔
650
        }
651

652
        if (parent != -1) {
1✔
653
            if (nodeBaseURI.isEmpty()) {
1✔
654
                baseURI = ((ElementImpl) document.getNode(parent))
1✔
655
                    .calculateBaseURI();
1✔
656
            } else {
1✔
657
                final XmldbURI parentsBaseURI = ((ElementImpl) document.getNode(parent)).calculateBaseURI();
1✔
658
                if (parentsBaseURI.toString().endsWith("/") || !parentsBaseURI.toString().contains("/")) {
1!
659
                    baseURI = parentsBaseURI.append(baseURI);
1✔
660
                } else {
1✔
661
                    // there is a filename, remove it
662
                    baseURI = parentsBaseURI.removeLastSegment().append(baseURI);
×
663
                }
664
            }
665
        } else {
×
666
            if (nodeBaseURI.isEmpty()) {
1!
667
                return XmldbURI.create(getOwnerDocument().getBaseURI(), false);
1✔
668
            } else if (nodeNumber != 1) {
×
669
                final String docBaseURI = getOwnerDocument().getBaseURI();
×
670
                if (docBaseURI.endsWith("/")) {
×
671
                    baseURI = XmldbURI.create(getOwnerDocument().getBaseURI(), false);
×
672
                    baseURI.append(baseURI);
×
673
                } else {
×
674
                    baseURI = XmldbURI.create(getOwnerDocument().getBaseURI(), false);
×
675
                    baseURI = baseURI.removeLastSegment();
×
676
                    baseURI.append(baseURI);
×
677
                }
678
            }
679
        }
680

681
        return baseURI;
1✔
682
    }
683

684
    @Override
685
    public TypeInfo getSchemaTypeInfo() {
686
        return null;
×
687
    }
688

689
    @Override
690
    public void setIdAttribute(final String name, final boolean isId) throws DOMException {
691
    }
×
692

693
    @Override
694
    public void setIdAttributeNS(final String namespaceURI, final String localName, final boolean isId)
695
        throws DOMException {
696
    }
×
697

698
    @Override
699
    public void setIdAttributeNode(final Attr idAttr, final boolean isId) throws DOMException {
700
    }
×
701

702
    @Override
703
    public void setTextContent(final String textContent) throws DOMException {
704
        final int nodeNr = document.addNode(Node.TEXT_NODE, (short) (document.getTreeLevel(nodeNumber) + 1), null);
×
705
        document.addChars(nodeNr, textContent.toCharArray(), 0, textContent.length());
×
706
    }
×
707

708
    @Override
709
    public String toString() {
710
        final StringBuilder result = new StringBuilder();
1✔
711
        result.append("in-memory#");
1✔
712
        result.append("element {");
1✔
713
        result.append(getQName().getStringValue());
1✔
714
        result.append("} {");
1✔
715
        final NamedNodeMap theAttrs = getAttributes();
1✔
716
        if(theAttrs != null) {
1!
717
            for(int i = 0; i < theAttrs.getLength(); i++) {
1✔
718
                if(i > 0) {
1!
719
                    result.append(" ");
×
720
                }
721
                final Node natt = theAttrs.item(i);
1✔
722
                result.append(natt.toString());
1✔
723
            }
724
        }
725
        for(int i = 0; i < this.getChildCount(); i++) {
1!
726
            if(i > 0) {
×
727
                result.append(" ");
×
728
            }
729
            final Node child = getChildNodes().item(i);
×
730
            result.append(child.toString());
×
731
        }
732
        result.append("} ");
1✔
733
        return result.toString();
1✔
734
    }
735

736
    @Override
737
    public String getTextContent() throws DOMException {
738
        final StringBuilder result = new StringBuilder();
1✔
739
        for(int i = 0; i < this.getChildCount(); i++) {
1✔
740
            final Node child = getChildNodes().item(i);
1✔
741
            if(child instanceof Text) {
1✔
742
                if(i > 0) {
1✔
743
                    result.append(" ");
1✔
744
                }
745
                result.append(((Text) child).getData());
1✔
746
            }
747
        }
748
        return result.toString();
1✔
749
    }
750

751
    @Override
752
    public Node appendChild(final Node newChild) throws DOMException {
753
        if(newChild.getNodeType() != Node.DOCUMENT_NODE && newChild.getOwnerDocument() != document) {
×
754
            throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, "Owning document IDs do not match");
×
755
        }
756

757
        if(newChild == this) {
×
758
            throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
×
759
                    "Cannot append an element to itself");
×
760
        }
761

762
        if(newChild.getNodeType() == DOCUMENT_NODE) {
×
763
            throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
×
764
                    "A Document Node may not be appended to an element");
×
765
        }
766

767
        if(newChild.getNodeType() == DOCUMENT_TYPE_NODE) {
×
768
            throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
×
769
                    "A Document Type Node may not be appended to an element");
×
770
        }
771

772
        if(newChild instanceof NodeImpl) {
×
773
            final int treeLevel = document.treeLevel[nodeNumber];
×
774
            final int newChildTreeLevel = document.treeLevel[((NodeImpl)newChild).nodeNumber];
×
775
            if(newChildTreeLevel < treeLevel) {
×
776
                throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
×
777
                        "The node to append is one of this node's ancestors");
×
778
            }
779
        }
780

781
        throw unsupported();
×
782
    }
783

784
    public String getAttributeValue(final String name) {
785
        int attr = 0;
×
786
        while (attr < document.nextAttr) {
×
787
            final QName attrQName = document.attrName[attr];
×
788
            if (attrQName.getStringValue().equals(name)) {
×
789
                return document.attrValue[attr];
×
790
            }
791
            ++attr;
×
792
        }
793
        return null;
×
794
    }
795
}
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