Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/xslt/xpath/txMozillaXPathTreeWalker.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#include "txXPathTreeWalker.h"
7
#include "nsAtom.h"
8
#include "nsINode.h"
9
#include "nsPrintfCString.h"
10
#include "nsReadableUtils.h"
11
#include "nsString.h"
12
#include "nsTextFragment.h"
13
#include "txXMLUtils.h"
14
#include "txLog.h"
15
#include "nsUnicharUtils.h"
16
#include "nsAttrName.h"
17
#include "nsTArray.h"
18
#include "mozilla/dom/Attr.h"
19
#include "mozilla/dom/CharacterData.h"
20
#include "mozilla/dom/Element.h"
21
#include <stdint.h>
22
#include <algorithm>
23
24
using namespace mozilla::dom;
25
26
txXPathTreeWalker::txXPathTreeWalker(const txXPathTreeWalker& aOther)
27
    : mPosition(aOther.mPosition)
28
0
{
29
0
}
30
31
txXPathTreeWalker::txXPathTreeWalker(const txXPathNode& aNode)
32
    : mPosition(aNode)
33
0
{
34
0
}
35
36
void
37
txXPathTreeWalker::moveToRoot()
38
0
{
39
0
    if (mPosition.isDocument()) {
40
0
        return;
41
0
    }
42
0
43
0
    nsIDocument* root = mPosition.mNode->GetUncomposedDoc();
44
0
    if (root) {
45
0
        mPosition.mIndex = txXPathNode::eDocument;
46
0
        mPosition.mNode = root;
47
0
    }
48
0
    else {
49
0
        nsINode *rootNode = mPosition.Root();
50
0
51
0
        NS_ASSERTION(rootNode->IsContent(),
52
0
                     "root of subtree wasn't an nsIContent");
53
0
54
0
        mPosition.mIndex = txXPathNode::eContent;
55
0
        mPosition.mNode = rootNode;
56
0
    }
57
0
}
58
59
bool
60
txXPathTreeWalker::moveToElementById(const nsAString& aID)
61
0
{
62
0
    if (aID.IsEmpty()) {
63
0
        return false;
64
0
    }
65
0
66
0
    nsIDocument* doc = mPosition.mNode->GetUncomposedDoc();
67
0
68
0
    nsCOMPtr<nsIContent> content;
69
0
    if (doc) {
70
0
        content = doc->GetElementById(aID);
71
0
    }
72
0
    else {
73
0
        // We're in a disconnected subtree, search only that subtree.
74
0
        nsINode *rootNode = mPosition.Root();
75
0
76
0
        NS_ASSERTION(rootNode->IsContent(),
77
0
                     "root of subtree wasn't an nsIContent");
78
0
79
0
        content = nsContentUtils::MatchElementId(
80
0
            static_cast<nsIContent*>(rootNode), aID);
81
0
    }
82
0
83
0
    if (!content) {
84
0
        return false;
85
0
    }
86
0
87
0
    mPosition.mIndex = txXPathNode::eContent;
88
0
    mPosition.mNode = content;
89
0
90
0
    return true;
91
0
}
92
93
bool
94
txXPathTreeWalker::moveToFirstAttribute()
95
0
{
96
0
    if (!mPosition.isContent()) {
97
0
        return false;
98
0
    }
99
0
100
0
    return moveToValidAttribute(0);
101
0
}
102
103
bool
104
txXPathTreeWalker::moveToNextAttribute()
105
0
{
106
0
    // XXX an assertion should be enough here with the current code
107
0
    if (!mPosition.isAttribute()) {
108
0
        return false;
109
0
    }
110
0
111
0
    return moveToValidAttribute(mPosition.mIndex + 1);
112
0
}
113
114
bool
115
txXPathTreeWalker::moveToValidAttribute(uint32_t aStartIndex)
116
0
{
117
0
    NS_ASSERTION(!mPosition.isDocument(), "documents doesn't have attrs");
118
0
119
0
    if (!mPosition.Content()->IsElement()) {
120
0
      return false;
121
0
    }
122
0
123
0
    Element* element = mPosition.Content()->AsElement();
124
0
    uint32_t total = element->GetAttrCount();
125
0
    if (aStartIndex >= total) {
126
0
        return false;
127
0
    }
128
0
129
0
    uint32_t index;
130
0
    for (index = aStartIndex; index < total; ++index) {
131
0
        const nsAttrName* name = element->GetAttrNameAt(index);
132
0
133
0
        // We need to ignore XMLNS attributes.
134
0
        if (name->NamespaceID() != kNameSpaceID_XMLNS) {
135
0
            mPosition.mIndex = index;
136
0
137
0
            return true;
138
0
        }
139
0
    }
140
0
    return false;
141
0
}
142
143
bool
144
txXPathTreeWalker::moveToNamedAttribute(nsAtom* aLocalName, int32_t aNSID)
145
0
{
146
0
    if (!mPosition.isContent() || !mPosition.Content()->IsElement()) {
147
0
        return false;
148
0
    }
149
0
150
0
    Element* element = mPosition.Content()->AsElement();
151
0
152
0
    const nsAttrName* name;
153
0
    uint32_t i;
154
0
    for (i = 0; (name = element->GetAttrNameAt(i)); ++i) {
155
0
        if (name->Equals(aLocalName, aNSID)) {
156
0
            mPosition.mIndex = i;
157
0
158
0
            return true;
159
0
        }
160
0
    }
161
0
    return false;
162
0
}
163
164
bool
165
txXPathTreeWalker::moveToFirstChild()
166
0
{
167
0
    if (mPosition.isAttribute()) {
168
0
        return false;
169
0
    }
170
0
171
0
    nsIContent* child = mPosition.mNode->GetFirstChild();
172
0
    if (!child) {
173
0
        return false;
174
0
    }
175
0
    mPosition.mIndex = txXPathNode::eContent;
176
0
    mPosition.mNode = child;
177
0
178
0
    return true;
179
0
}
180
181
bool
182
txXPathTreeWalker::moveToLastChild()
183
0
{
184
0
    if (mPosition.isAttribute()) {
185
0
        return false;
186
0
    }
187
0
188
0
    nsIContent* child = mPosition.mNode->GetLastChild();
189
0
    if (!child) {
190
0
        return false;
191
0
    }
192
0
193
0
    mPosition.mIndex = txXPathNode::eContent;
194
0
    mPosition.mNode = child;
195
0
196
0
    return true;
197
0
}
198
199
bool
200
txXPathTreeWalker::moveToNextSibling()
201
0
{
202
0
    if (!mPosition.isContent()) {
203
0
        return false;
204
0
    }
205
0
206
0
    nsINode* sibling = mPosition.mNode->GetNextSibling();
207
0
    if (!sibling) {
208
0
      return false;
209
0
    }
210
0
211
0
    mPosition.mNode = sibling;
212
0
213
0
    return true;
214
0
}
215
216
bool
217
txXPathTreeWalker::moveToPreviousSibling()
218
0
{
219
0
    if (!mPosition.isContent()) {
220
0
        return false;
221
0
    }
222
0
223
0
    nsINode* sibling = mPosition.mNode->GetPreviousSibling();
224
0
    if (!sibling) {
225
0
      return false;
226
0
    }
227
0
228
0
    mPosition.mNode = sibling;
229
0
230
0
    return true;
231
0
}
232
233
bool
234
txXPathTreeWalker::moveToParent()
235
0
{
236
0
    if (mPosition.isDocument()) {
237
0
        return false;
238
0
    }
239
0
240
0
    if (mPosition.isAttribute()) {
241
0
        mPosition.mIndex = txXPathNode::eContent;
242
0
243
0
        return true;
244
0
    }
245
0
246
0
    nsINode* parent = mPosition.mNode->GetParentNode();
247
0
    if (!parent) {
248
0
        return false;
249
0
    }
250
0
251
0
    mPosition.mIndex = mPosition.mNode->GetParent() ?
252
0
      txXPathNode::eContent : txXPathNode::eDocument;
253
0
    mPosition.mNode = parent;
254
0
255
0
    return true;
256
0
}
257
258
txXPathNode::txXPathNode(const txXPathNode& aNode)
259
  : mNode(aNode.mNode),
260
    mRefCountRoot(aNode.mRefCountRoot),
261
    mIndex(aNode.mIndex)
262
0
{
263
0
    MOZ_COUNT_CTOR(txXPathNode);
264
0
    if (mRefCountRoot) {
265
0
        NS_ADDREF(Root());
266
0
    }
267
0
}
268
269
txXPathNode::~txXPathNode()
270
0
{
271
0
    MOZ_COUNT_DTOR(txXPathNode);
272
0
    if (mRefCountRoot) {
273
0
        nsINode *root = Root();
274
0
        NS_RELEASE(root);
275
0
    }
276
0
}
277
278
/* static */
279
bool
280
txXPathNodeUtils::getAttr(const txXPathNode& aNode, nsAtom* aLocalName,
281
                          int32_t aNSID, nsAString& aValue)
282
0
{
283
0
    if (aNode.isDocument() || aNode.isAttribute() ||
284
0
        !aNode.Content()->IsElement()) {
285
0
        return false;
286
0
    }
287
0
288
0
    return aNode.Content()->AsElement()->GetAttr(aNSID, aLocalName, aValue);
289
0
}
290
291
/* static */
292
already_AddRefed<nsAtom>
293
txXPathNodeUtils::getLocalName(const txXPathNode& aNode)
294
0
{
295
0
    if (aNode.isDocument()) {
296
0
        return nullptr;
297
0
    }
298
0
299
0
    if (aNode.isContent()) {
300
0
        if (aNode.mNode->IsElement()) {
301
0
            RefPtr<nsAtom> localName =
302
0
                aNode.Content()->NodeInfo()->NameAtom();
303
0
            return localName.forget();
304
0
        }
305
0
306
0
        if (aNode.mNode->IsProcessingInstruction()) {
307
0
            return NS_Atomize(aNode.mNode->NodeName());
308
0
        }
309
0
310
0
        return nullptr;
311
0
    }
312
0
313
0
    // This is an attribute node, so we necessarily come from an element.
314
0
    RefPtr<nsAtom> localName =
315
0
      aNode.Content()->AsElement()->GetAttrNameAt(aNode.mIndex)->LocalName();
316
0
317
0
    return localName.forget();
318
0
}
319
320
nsAtom*
321
txXPathNodeUtils::getPrefix(const txXPathNode& aNode)
322
0
{
323
0
    if (aNode.isDocument()) {
324
0
        return nullptr;
325
0
    }
326
0
327
0
    if (aNode.isContent()) {
328
0
        // All other nsIContent node types but elements have a null prefix
329
0
        // which is what we want here.
330
0
        return aNode.Content()->NodeInfo()->GetPrefixAtom();
331
0
    }
332
0
333
0
    return aNode.Content()->AsElement()->GetAttrNameAt(aNode.mIndex)->GetPrefix();
334
0
}
335
336
/* static */
337
void
338
txXPathNodeUtils::getLocalName(const txXPathNode& aNode, nsAString& aLocalName)
339
0
{
340
0
    if (aNode.isDocument()) {
341
0
        aLocalName.Truncate();
342
0
343
0
        return;
344
0
    }
345
0
346
0
    if (aNode.isContent()) {
347
0
        if (aNode.mNode->IsElement()) {
348
0
            mozilla::dom::NodeInfo* nodeInfo = aNode.Content()->NodeInfo();
349
0
            nodeInfo->GetName(aLocalName);
350
0
            return;
351
0
        }
352
0
353
0
        if (aNode.mNode->IsProcessingInstruction()) {
354
0
            // PIs don't have a nodeinfo but do have a name
355
0
            // XXXbz Not actually true, but this function looks like it wants
356
0
            // different things from elements and PIs for "local name"...
357
0
            aLocalName = aNode.mNode->NodeName();
358
0
            return;
359
0
        }
360
0
361
0
        aLocalName.Truncate();
362
0
363
0
        return;
364
0
    }
365
0
366
0
    aNode.Content()->AsElement()->GetAttrNameAt(aNode.mIndex)->LocalName()->
367
0
      ToString(aLocalName);
368
0
369
0
    // Check for html
370
0
    if (aNode.Content()->NodeInfo()->NamespaceEquals(kNameSpaceID_None) &&
371
0
        aNode.Content()->IsHTMLElement()) {
372
0
        nsContentUtils::ASCIIToUpper(aLocalName);
373
0
    }
374
0
}
375
376
/* static */
377
void
378
txXPathNodeUtils::getNodeName(const txXPathNode& aNode, nsAString& aName)
379
0
{
380
0
    if (aNode.isDocument()) {
381
0
        aName.Truncate();
382
0
383
0
        return;
384
0
    }
385
0
386
0
    if (aNode.isContent()) {
387
0
        // Elements and PIs have a name
388
0
        if (aNode.mNode->IsElement() ||
389
0
            aNode.mNode->NodeType() == nsINode::PROCESSING_INSTRUCTION_NODE) {
390
0
            aName = aNode.Content()->NodeName();
391
0
            return;
392
0
        }
393
0
394
0
        aName.Truncate();
395
0
396
0
        return;
397
0
    }
398
0
399
0
    aNode.Content()->AsElement()->GetAttrNameAt(aNode.mIndex)->GetQualifiedName(aName);
400
0
}
401
402
/* static */
403
int32_t
404
txXPathNodeUtils::getNamespaceID(const txXPathNode& aNode)
405
0
{
406
0
    if (aNode.isDocument()) {
407
0
        return kNameSpaceID_None;
408
0
    }
409
0
410
0
    if (aNode.isContent()) {
411
0
        return aNode.Content()->GetNameSpaceID();
412
0
    }
413
0
414
0
    return aNode.Content()->AsElement()->GetAttrNameAt(aNode.mIndex)->NamespaceID();
415
0
}
416
417
/* static */
418
void
419
txXPathNodeUtils::getNamespaceURI(const txXPathNode& aNode, nsAString& aURI)
420
0
{
421
0
    nsContentUtils::NameSpaceManager()->GetNameSpaceURI(getNamespaceID(aNode), aURI);
422
0
}
423
424
/* static */
425
uint16_t
426
txXPathNodeUtils::getNodeType(const txXPathNode& aNode)
427
0
{
428
0
    if (aNode.isDocument()) {
429
0
        return txXPathNodeType::DOCUMENT_NODE;
430
0
    }
431
0
432
0
    if (aNode.isContent()) {
433
0
        return aNode.mNode->NodeType();
434
0
    }
435
0
436
0
    return txXPathNodeType::ATTRIBUTE_NODE;
437
0
}
438
439
/* static */
440
void
441
txXPathNodeUtils::appendNodeValue(const txXPathNode& aNode, nsAString& aResult)
442
0
{
443
0
    if (aNode.isAttribute()) {
444
0
        const nsAttrName* name = aNode.Content()->AsElement()->GetAttrNameAt(aNode.mIndex);
445
0
446
0
        if (aResult.IsEmpty()) {
447
0
            aNode.Content()->AsElement()->GetAttr(name->NamespaceID(),
448
0
                                                  name->LocalName(),
449
0
                                                  aResult);
450
0
        } else {
451
0
            nsAutoString result;
452
0
            aNode.Content()->AsElement()->GetAttr(name->NamespaceID(),
453
0
                                                  name->LocalName(),
454
0
                                                  result);
455
0
            aResult.Append(result);
456
0
        }
457
0
458
0
        return;
459
0
    }
460
0
461
0
    if (aNode.isDocument() ||
462
0
        aNode.mNode->IsElement() ||
463
0
        aNode.mNode->IsDocumentFragment()) {
464
0
        nsContentUtils::AppendNodeTextContent(aNode.mNode, true, aResult,
465
0
                                              mozilla::fallible);
466
0
467
0
        return;
468
0
    }
469
0
470
0
    MOZ_ASSERT(aNode.mNode->IsCharacterData());
471
0
    static_cast<CharacterData*>(aNode.Content())->AppendTextTo(aResult);
472
0
}
473
474
/* static */
475
bool
476
txXPathNodeUtils::isWhitespace(const txXPathNode& aNode)
477
0
{
478
0
    NS_ASSERTION(aNode.isContent() && isText(aNode), "Wrong type!");
479
0
480
0
    return aNode.Content()->TextIsOnlyWhitespace();
481
0
}
482
483
/* static */
484
txXPathNode*
485
txXPathNodeUtils::getOwnerDocument(const txXPathNode& aNode)
486
0
{
487
0
    return new txXPathNode(aNode.mNode->OwnerDoc());
488
0
}
489
490
const char gPrintfFmt[] = "id0x%" PRIxPTR;
491
const char gPrintfFmtAttr[] = "id0x%" PRIxPTR "-%010i";
492
493
/* static */
494
nsresult
495
txXPathNodeUtils::getXSLTId(const txXPathNode& aNode,
496
                            const txXPathNode& aBase,
497
                            nsAString& aResult)
498
0
{
499
0
    uintptr_t nodeid = ((uintptr_t)aNode.mNode) - ((uintptr_t)aBase.mNode);
500
0
    if (!aNode.isAttribute()) {
501
0
        CopyASCIItoUTF16(nsPrintfCString(gPrintfFmt, nodeid),
502
0
                         aResult);
503
0
    }
504
0
    else {
505
0
        CopyASCIItoUTF16(nsPrintfCString(gPrintfFmtAttr,
506
0
                                         nodeid, aNode.mIndex), aResult);
507
0
    }
508
0
509
0
    return NS_OK;
510
0
}
511
512
/* static */
513
nsresult
514
txXPathNodeUtils::getBaseURI(const txXPathNode& aNode, nsAString& aURI)
515
0
{
516
0
    return aNode.mNode->GetBaseURI(aURI);
517
0
}
518
519
/* static */
520
int
521
txXPathNodeUtils::comparePosition(const txXPathNode& aNode,
522
                                  const txXPathNode& aOtherNode)
523
0
{
524
0
    // First check for equal nodes or attribute-nodes on the same element.
525
0
    if (aNode.mNode == aOtherNode.mNode) {
526
0
        if (aNode.mIndex == aOtherNode.mIndex) {
527
0
            return 0;
528
0
        }
529
0
530
0
        NS_ASSERTION(!aNode.isDocument() && !aOtherNode.isDocument(),
531
0
                     "documents should always have a set index");
532
0
533
0
        if (aNode.isContent() || (!aOtherNode.isContent() &&
534
0
                                  aNode.mIndex < aOtherNode.mIndex)) {
535
0
            return -1;
536
0
        }
537
0
538
0
        return 1;
539
0
    }
540
0
541
0
    // Get document for both nodes.
542
0
    nsIDocument* document = aNode.mNode->GetUncomposedDoc();
543
0
    nsIDocument* otherDocument = aOtherNode.mNode->GetUncomposedDoc();
544
0
545
0
    // If the nodes have different current documents, compare the document
546
0
    // pointers.
547
0
    if (document != otherDocument) {
548
0
        return document < otherDocument ? -1 : 1;
549
0
    }
550
0
551
0
    // Now either both nodes are in orphan trees, or they are both in the
552
0
    // same tree.
553
0
554
0
    // Get parents up the tree.
555
0
    AutoTArray<nsINode*, 8> parents, otherParents;
556
0
    nsINode* node = aNode.mNode;
557
0
    nsINode* otherNode = aOtherNode.mNode;
558
0
    nsINode* parent;
559
0
    nsINode* otherParent;
560
0
    while (node && otherNode) {
561
0
        parent = node->GetParentNode();
562
0
        otherParent = otherNode->GetParentNode();
563
0
564
0
        // Hopefully this is a common case.
565
0
        if (parent == otherParent) {
566
0
            if (!parent) {
567
0
                // Both node and otherNode are root nodes in respective orphan
568
0
                // tree.
569
0
                return node < otherNode ? -1 : 1;
570
0
            }
571
0
572
0
            return parent->ComputeIndexOf(node) < parent->ComputeIndexOf(otherNode) ?
573
0
                   -1 : 1;
574
0
        }
575
0
576
0
        parents.AppendElement(node);
577
0
        otherParents.AppendElement(otherNode);
578
0
        node = parent;
579
0
        otherNode = otherParent;
580
0
    }
581
0
582
0
    while (node) {
583
0
        parents.AppendElement(node);
584
0
        node = node->GetParentNode();
585
0
    }
586
0
    while (otherNode) {
587
0
        otherParents.AppendElement(otherNode);
588
0
        otherNode = otherNode->GetParentNode();
589
0
    }
590
0
591
0
    // Walk back down along the parent-chains until we find where they split.
592
0
    int32_t total = parents.Length() - 1;
593
0
    int32_t otherTotal = otherParents.Length() - 1;
594
0
    NS_ASSERTION(total != otherTotal, "Can't have same number of parents");
595
0
596
0
    int32_t lastIndex = std::min(total, otherTotal);
597
0
    int32_t i;
598
0
    parent = nullptr;
599
0
    for (i = 0; i <= lastIndex; ++i) {
600
0
        node = parents.ElementAt(total - i);
601
0
        otherNode = otherParents.ElementAt(otherTotal - i);
602
0
        if (node != otherNode) {
603
0
            if (!parent) {
604
0
                // The two nodes are in different orphan subtrees.
605
0
                NS_ASSERTION(i == 0, "this shouldn't happen");
606
0
                return node < otherNode ? -1 : 1;
607
0
            }
608
0
609
0
            int32_t index = parent->ComputeIndexOf(node);
610
0
            int32_t otherIndex = parent->ComputeIndexOf(otherNode);
611
0
            NS_ASSERTION(index != otherIndex && index >= 0 && otherIndex >= 0,
612
0
                         "invalid index in compareTreePosition");
613
0
614
0
            return index < otherIndex ? -1 : 1;
615
0
        }
616
0
617
0
        parent = node;
618
0
    }
619
0
620
0
    // One node is a descendant of the other. The one with the shortest
621
0
    // parent-chain is first in the document.
622
0
    return total < otherTotal ? -1 : 1;
623
0
}
624
625
/* static */
626
txXPathNode*
627
txXPathNativeNode::createXPathNode(nsIContent* aContent, bool aKeepRootAlive)
628
0
{
629
0
    nsINode* root = aKeepRootAlive ? txXPathNode::RootOf(aContent) : nullptr;
630
0
631
0
    return new txXPathNode(aContent, txXPathNode::eContent, root);
632
0
}
633
634
/* static */
635
txXPathNode*
636
txXPathNativeNode::createXPathNode(nsINode* aNode, bool aKeepRootAlive)
637
0
{
638
0
    uint16_t nodeType = aNode->NodeType();
639
0
    if (nodeType == nsINode::ATTRIBUTE_NODE) {
640
0
        auto* attr = static_cast<Attr*>(aNode);
641
0
642
0
        NodeInfo* nodeInfo = attr->NodeInfo();
643
0
        Element* parent = attr->GetElement();
644
0
        if (!parent) {
645
0
            return nullptr;
646
0
        }
647
0
648
0
        nsINode* root = aKeepRootAlive ? txXPathNode::RootOf(parent) : nullptr;
649
0
650
0
        uint32_t i, total = parent->GetAttrCount();
651
0
        for (i = 0; i < total; ++i) {
652
0
            const nsAttrName* name = parent->GetAttrNameAt(i);
653
0
            if (nodeInfo->Equals(name->LocalName(), name->NamespaceID())) {
654
0
                return new txXPathNode(parent, i, root);
655
0
            }
656
0
        }
657
0
658
0
        NS_ERROR("Couldn't find the attribute in its parent!");
659
0
660
0
        return nullptr;
661
0
    }
662
0
663
0
    uint32_t index;
664
0
    nsINode* root = aKeepRootAlive ? aNode : nullptr;
665
0
666
0
    if (nodeType == nsINode::DOCUMENT_NODE) {
667
0
        index = txXPathNode::eDocument;
668
0
    }
669
0
    else {
670
0
        index = txXPathNode::eContent;
671
0
        if (root) {
672
0
            root = txXPathNode::RootOf(root);
673
0
        }
674
0
    }
675
0
676
0
    return new txXPathNode(aNode, index, root);
677
0
}
678
679
/* static */
680
txXPathNode*
681
txXPathNativeNode::createXPathNode(nsIDocument* aDocument)
682
0
{
683
0
    return new txXPathNode(aDocument);
684
0
}
685
686
/* static */
687
nsINode*
688
txXPathNativeNode::getNode(const txXPathNode& aNode)
689
0
{
690
0
    if (!aNode.isAttribute()) {
691
0
        return aNode.mNode;
692
0
    }
693
0
694
0
    const nsAttrName* name =
695
0
      aNode.Content()->AsElement()->GetAttrNameAt(aNode.mIndex);
696
0
697
0
    nsAutoString namespaceURI;
698
0
    nsContentUtils::NameSpaceManager()->GetNameSpaceURI(name->NamespaceID(), namespaceURI);
699
0
700
0
    nsCOMPtr<Element> element = do_QueryInterface(aNode.mNode);
701
0
    nsDOMAttributeMap* map = element->Attributes();
702
0
    return map->GetNamedItemNS(namespaceURI,
703
0
                               nsDependentAtomString(name->LocalName()));
704
0
}
705
706
/* static */
707
nsIContent*
708
txXPathNativeNode::getContent(const txXPathNode& aNode)
709
0
{
710
0
    NS_ASSERTION(aNode.isContent(),
711
0
                 "Only call getContent on nsIContent wrappers!");
712
0
    return aNode.Content();
713
0
}
714
715
/* static */
716
nsIDocument*
717
txXPathNativeNode::getDocument(const txXPathNode& aNode)
718
0
{
719
0
    NS_ASSERTION(aNode.isDocument(),
720
0
                 "Only call getDocument on nsIDocument wrappers!");
721
0
    return aNode.Document();
722
0
}