예제 #1
0
Value LocationPath::evaluate() const
{
    EvaluationContext& evaluationContext = Expression::evaluationContext();
    EvaluationContext backupContext = evaluationContext;
    // http://www.w3.org/TR/xpath/
    // Section 2, Location Paths:
    // "/ selects the document root (which is always the parent of the document element)"
    // "A / by itself selects the root node of the document containing the context node."
    // In the case of a tree that is detached from the document, we violate
    // the spec and treat / as the root node of the detached tree.
    // This is for compatibility with Firefox, and also seems like a more
    // logical treatment of where you would expect the "root" to be.
    Node* context = evaluationContext.node.get();
    if (m_absolute && context->nodeType() != Node::DOCUMENT_NODE)  {
        if (context->inDocument())
            context = context->ownerDocument();
        else
            context = context->highestAncestor();
    }

    NodeSet nodes;
    nodes.append(context);
    evaluate(nodes);
    
    evaluationContext = backupContext;
    return Value(nodes, Value::adopt);
}
예제 #2
0
파일: XPathStep.cpp 프로젝트: Igalia/blink
void Step::evaluate(Node* context, NodeSet& nodes) const
{
    EvaluationContext& evaluationContext = Expression::evaluationContext();
    evaluationContext.position = 0;

    nodesInAxis(context, nodes);

    // Check predicates that couldn't be merged into node test.
    for (unsigned i = 0; i < m_predicates.size(); i++) {
        Predicate* predicate = m_predicates[i].get();

        NodeSet newNodes;
        if (!nodes.isSorted())
            newNodes.markSorted(false);

        for (unsigned j = 0; j < nodes.size(); j++) {
            Node* node = nodes[j];

            evaluationContext.node = node;
            evaluationContext.size = nodes.size();
            evaluationContext.position = j + 1;
            if (predicate->evaluate())
                newNodes.append(node);
        }

        nodes.swap(newNodes);
    }
}
예제 #3
0
Value Filter::evaluate() const
{
    Value v = m_expr->evaluate();
    
    NodeSet& nodes = v.modifiableNodeSet();
    nodes.sort();

    EvaluationContext& evaluationContext = Expression::evaluationContext();
    for (unsigned i = 0; i < m_predicates.size(); i++) {
        NodeSet newNodes;
        evaluationContext.size = nodes.size();
        evaluationContext.position = 0;
        
        for (unsigned j = 0; j < nodes.size(); j++) {
            Node* node = nodes[j];
            
            evaluationContext.node = node;
            ++evaluationContext.position;
            
            if (m_predicates[i]->evaluate())
                newNodes.append(node);
        }
        nodes.swap(newNodes);
    }

    return v;
}
예제 #4
0
void Step::evaluate(Node* context, NodeSet& nodes) const
{
    nodesInAxis(context, nodes);
    
    EvaluationContext& evaluationContext = Expression::evaluationContext();
    
    for (unsigned i = 0; i < m_predicates.size(); i++) {
        Predicate* predicate = m_predicates[i];

        NodeSet newNodes;
        if (!nodes.isSorted())
            newNodes.markSorted(false);

        evaluationContext.size = nodes.size();
        evaluationContext.position = 1;
        for (unsigned j = 0; j < nodes.size(); j++) {
            Node* node = nodes[j];

            Expression::evaluationContext().node = node;
            EvaluationContext backupCtx = evaluationContext;
            if (predicate->evaluate())
                newNodes.append(node);

            evaluationContext = backupCtx;
            ++evaluationContext.position;
        }

        nodes.swap(newNodes);
    }
}
예제 #5
0
Value Filter::evaluate() const
{
    Value result = m_expression->evaluate();
    
    NodeSet& nodes = result.modifiableNodeSet();
    nodes.sort();

    EvaluationContext& evaluationContext = Expression::evaluationContext();
    for (unsigned i = 0; i < m_predicates.size(); i++) {
        NodeSet newNodes;
        evaluationContext.size = nodes.size();
        evaluationContext.position = 0;
        
        for (unsigned j = 0; j < nodes.size(); j++) {
            Node* node = nodes[j];
            
            evaluationContext.node = node;
            ++evaluationContext.position;
            
            if (evaluatePredicate(*m_predicates[i]))
                newNodes.append(node);
        }
        nodes = WTF::move(newNodes);
    }

    return result;
}
예제 #6
0
Value Filter::evaluate() const
{
    Value result = m_expression->evaluate();
    
    NodeSet& nodes = result.modifiableNodeSet();
    nodes.sort();

    EvaluationContext& evaluationContext = Expression::evaluationContext();
    for (auto& predicate : m_predicates) {
        NodeSet newNodes;
        evaluationContext.size = nodes.size();
        evaluationContext.position = 0;
        
        for (auto& node : nodes) {
            evaluationContext.node = node;
            ++evaluationContext.position;
            
            if (evaluatePredicate(*predicate))
                newNodes.append(node.copyRef());
        }
        nodes = WTFMove(newNodes);
    }

    return result;
}
예제 #7
0
Value LocationPath::evaluate() const
{
    EvaluationContext& evaluationContext = Expression::evaluationContext();
    EvaluationContext backupContext = evaluationContext;
    // For absolute location paths, the context node is ignored - the
    // document's root node is used instead.
    Node* context = evaluationContext.node.get();
    if (m_absolute && context->nodeType() != Node::DOCUMENT_NODE) 
        context = context->ownerDocument();

    NodeSet nodes;
    nodes.append(context);
    evaluate(nodes);
    
    evaluationContext = backupContext;
    return Value(nodes, Value::adopt);
}
예제 #8
0
Value FunId::evaluate() const
{
    Value a = argument(0).evaluate();
    StringBuilder idList; // A whitespace-separated list of IDs

    if (!a.isNodeSet())
        idList.append(a.toString());
    else {
        for (auto& node : a.toNodeSet()) {
            idList.append(stringValue(node.get()));
            idList.append(' ');
        }
    }
    
    TreeScope& contextScope = evaluationContext().node->treeScope();
    NodeSet result;
    HashSet<Node*> resultSet;

    unsigned startPos = 0;
    unsigned length = idList.length();
    while (true) {
        while (startPos < length && isWhitespace(idList[startPos]))
            ++startPos;
        
        if (startPos == length)
            break;

        size_t endPos = startPos;
        while (endPos < length && !isWhitespace(idList[endPos]))
            ++endPos;

        // If there are several nodes with the same id, id() should return the first one.
        // In WebKit, getElementById behaves so, too, although its behavior in this case is formally undefined.
        Node* node = contextScope.getElementById(atomicSubstring(idList, startPos, endPos - startPos));
        if (node && resultSet.add(node).isNewEntry)
            result.append(node);
        
        startPos = endPos;
    }
    
    result.markSorted(false);
    
    return Value(WTFMove(result));
}
예제 #9
0
void LocationPath::evaluate(NodeSet& nodes) const
{
    bool resultIsSorted = nodes.isSorted();

    for (unsigned i = 0; i < m_steps.size(); i++) {
        Step* step = m_steps[i];
        NodeSet newNodes;
        HashSet<Node*> newNodesSet;

        bool needToCheckForDuplicateNodes = !nodes.subtreesAreDisjoint() || (step->axis() != Step::ChildAxis && step->axis() != Step::SelfAxis
            && step->axis() != Step::DescendantAxis && step->axis() != Step::DescendantOrSelfAxis && step->axis() != Step::AttributeAxis);

        if (needToCheckForDuplicateNodes)
            resultIsSorted = false;

        // This is a simplified check that can be improved to handle more cases.
        if (nodes.subtreesAreDisjoint() && (step->axis() == Step::ChildAxis || step->axis() == Step::SelfAxis))
            newNodes.markSubtreesDisjoint(true);

        for (unsigned j = 0; j < nodes.size(); j++) {
            NodeSet matches;
            step->evaluate(nodes[j], matches);

            if (!matches.isSorted())
                resultIsSorted = false;

            for (size_t nodeIndex = 0; nodeIndex < matches.size(); ++nodeIndex) {
                Node* node = matches[nodeIndex];
                if (!needToCheckForDuplicateNodes || newNodesSet.add(node).isNewEntry)
                    newNodes.append(node);
            }
        }
        
        nodes.swap(newNodes);
    }

    nodes.markSorted(resultIsSorted);
}
예제 #10
0
Value LocationPath::evaluate() const
{
    EvaluationContext& evaluationContext = Expression::evaluationContext();
    EvaluationContext backupContext = evaluationContext;
    // http://www.w3.org/TR/xpath/
    // Section 2, Location Paths:
    // "/ selects the document root (which is always the parent of the document element)"
    // "A / by itself selects the root node of the document containing the context node."
    // In the case of a tree that is detached from the document, we violate
    // the spec and treat / as the root node of the detached tree.
    // This is for compatibility with Firefox, and also seems like a more
    // logical treatment of where you would expect the "root" to be.
    Node* context = evaluationContext.node.get();
    if (m_isAbsolute && !context->isDocumentNode())
        context = &context->rootNode();

    NodeSet nodes;
    nodes.append(context);
    evaluate(nodes);
    
    evaluationContext = backupContext;
    return Value(WTFMove(nodes));
}
예제 #11
0
void LocationPath::evaluate(NodeSet& nodes) const
{
    bool resultIsSorted = nodes.isSorted();

    for (auto& step : m_steps) {
        NodeSet newNodes;
        HashSet<Node*> newNodesSet;

        bool needToCheckForDuplicateNodes = !nodes.subtreesAreDisjoint() || (step->axis() != Step::ChildAxis && step->axis() != Step::SelfAxis
            && step->axis() != Step::DescendantAxis && step->axis() != Step::DescendantOrSelfAxis && step->axis() != Step::AttributeAxis);

        if (needToCheckForDuplicateNodes)
            resultIsSorted = false;

        // This is a simplified check that can be improved to handle more cases.
        if (nodes.subtreesAreDisjoint() && (step->axis() == Step::ChildAxis || step->axis() == Step::SelfAxis))
            newNodes.markSubtreesDisjoint(true);

        for (auto& node : nodes) {
            NodeSet matches;
            step->evaluate(*node, matches);

            if (!matches.isSorted())
                resultIsSorted = false;

            for (auto& match : matches) {
                if (!needToCheckForDuplicateNodes || newNodesSet.add(match.get()).isNewEntry)
                    newNodes.append(match.copyRef());
            }
        }
        
        nodes = WTFMove(newNodes);
    }

    nodes.markSorted(resultIsSorted);
}
예제 #12
0
파일: XPathStep.cpp 프로젝트: Igalia/blink
// Result nodes are ordered in axis order. Node test (including merged predicates) is applied.
void Step::nodesInAxis(Node* context, NodeSet& nodes) const
{
    ASSERT(nodes.isEmpty());
    switch (m_axis) {
        case ChildAxis:
            if (context->isAttributeNode()) // In XPath model, attribute nodes do not have children.
                return;

            for (Node* n = context->firstChild(); n; n = n->nextSibling())
                if (nodeMatches(n, ChildAxis, m_nodeTest))
                    nodes.append(n);
            return;
        case DescendantAxis:
            if (context->isAttributeNode()) // In XPath model, attribute nodes do not have children.
                return;

            for (Node* n = context->firstChild(); n; n = NodeTraversal::next(*n, context))
                if (nodeMatches(n, DescendantAxis, m_nodeTest))
                    nodes.append(n);
            return;
        case ParentAxis:
            if (context->isAttributeNode()) {
                Element* n = toAttr(context)->ownerElement();
                if (nodeMatches(n, ParentAxis, m_nodeTest))
                    nodes.append(n);
            } else {
                ContainerNode* n = context->parentNode();
                if (n && nodeMatches(n, ParentAxis, m_nodeTest))
                    nodes.append(n);
            }
            return;
        case AncestorAxis: {
            Node* n = context;
            if (context->isAttributeNode()) {
                n = toAttr(context)->ownerElement();
                if (nodeMatches(n, AncestorAxis, m_nodeTest))
                    nodes.append(n);
            }
            for (n = n->parentNode(); n; n = n->parentNode())
                if (nodeMatches(n, AncestorAxis, m_nodeTest))
                    nodes.append(n);
            nodes.markSorted(false);
            return;
        }
        case FollowingSiblingAxis:
            if (context->nodeType() == Node::ATTRIBUTE_NODE ||
                 context->nodeType() == Node::XPATH_NAMESPACE_NODE)
                return;

            for (Node* n = context->nextSibling(); n; n = n->nextSibling())
                if (nodeMatches(n, FollowingSiblingAxis, m_nodeTest))
                    nodes.append(n);
            return;
        case PrecedingSiblingAxis:
            if (context->nodeType() == Node::ATTRIBUTE_NODE ||
                 context->nodeType() == Node::XPATH_NAMESPACE_NODE)
                return;

            for (Node* n = context->previousSibling(); n; n = n->previousSibling())
                if (nodeMatches(n, PrecedingSiblingAxis, m_nodeTest))
                    nodes.append(n);

            nodes.markSorted(false);
            return;
        case FollowingAxis:
            if (context->isAttributeNode()) {
                Node* p = toAttr(context)->ownerElement();
                while ((p = NodeTraversal::next(*p))) {
                    if (nodeMatches(p, FollowingAxis, m_nodeTest))
                        nodes.append(p);
                }
            } else {
                for (Node* p = context; !isRootDomNode(p); p = p->parentNode()) {
                    for (Node* n = p->nextSibling(); n; n = n->nextSibling()) {
                        if (nodeMatches(n, FollowingAxis, m_nodeTest))
                            nodes.append(n);
                        for (Node* c = n->firstChild(); c; c = NodeTraversal::next(*c, n))
                            if (nodeMatches(c, FollowingAxis, m_nodeTest))
                                nodes.append(c);
                    }
                }
            }
            return;
        case PrecedingAxis: {
            if (context->isAttributeNode())
                context = toAttr(context)->ownerElement();

            Node* n = context;
            while (ContainerNode* parent = n->parentNode()) {
                for (n = NodeTraversal::previous(*n); n != parent; n = NodeTraversal::previous(*n))
                    if (nodeMatches(n, PrecedingAxis, m_nodeTest))
                        nodes.append(n);
                n = parent;
            }
            nodes.markSorted(false);
            return;
        }
        case AttributeAxis: {
            if (!context->isElementNode())
                return;

            Element* contextElement = toElement(context);

            // Avoid lazily creating attribute nodes for attributes that we do not need anyway.
            if (m_nodeTest.kind() == NodeTest::NameTest && m_nodeTest.data() != starAtom) {
                RefPtr<Node> n = contextElement->getAttributeNodeNS(m_nodeTest.namespaceURI(), m_nodeTest.data());
                if (n && n->namespaceURI() != XMLNSNames::xmlnsNamespaceURI) { // In XPath land, namespace nodes are not accessible on the attribute axis.
                    if (nodeMatches(n.get(), AttributeAxis, m_nodeTest)) // Still need to check merged predicates.
                        nodes.append(n.release());
                }
                return;
            }

            if (!contextElement->hasAttributes())
                return;

            for (unsigned i = 0; i < contextElement->attributeCount(); ++i) {
                RefPtr<Attr> attr = contextElement->ensureAttr(contextElement->attributeItem(i)->name());
                if (nodeMatches(attr.get(), AttributeAxis, m_nodeTest))
                    nodes.append(attr.release());
            }
            return;
        }
        case NamespaceAxis:
            // XPath namespace nodes are not implemented yet.
            return;
        case SelfAxis:
            if (nodeMatches(context, SelfAxis, m_nodeTest))
                nodes.append(context);
            return;
        case DescendantOrSelfAxis:
            if (nodeMatches(context, DescendantOrSelfAxis, m_nodeTest))
                nodes.append(context);
            if (context->isAttributeNode()) // In XPath model, attribute nodes do not have children.
                return;

            for (Node* n = context->firstChild(); n; n = NodeTraversal::next(*n, context))
            if (nodeMatches(n, DescendantOrSelfAxis, m_nodeTest))
                nodes.append(n);
            return;
        case AncestorOrSelfAxis: {
            if (nodeMatches(context, AncestorOrSelfAxis, m_nodeTest))
                nodes.append(context);
            Node* n = context;
            if (context->isAttributeNode()) {
                n = toAttr(context)->ownerElement();
                if (nodeMatches(n, AncestorOrSelfAxis, m_nodeTest))
                    nodes.append(n);
            }
            for (n = n->parentNode(); n; n = n->parentNode())
                if (nodeMatches(n, AncestorOrSelfAxis, m_nodeTest))
                    nodes.append(n);

            nodes.markSorted(false);
            return;
        }
    }
    ASSERT_NOT_REACHED();
}
예제 #13
0
// Result nodes are ordered in axis order. Node test (including merged
// predicates) is applied.
void Step::nodesInAxis(EvaluationContext& evaluationContext, Node* context, NodeSet& nodes) const
{
    ASSERT(nodes.isEmpty());
    switch (m_axis) {
    case ChildAxis:
        // In XPath model, attribute nodes do not have children.
        if (context->isAttributeNode())
            return;

        for (Node* n = context->firstChild(); n; n = n->nextSibling()) {
            if (nodeMatches(evaluationContext, n, ChildAxis, nodeTest()))
                nodes.append(n);
        }
        return;

    case DescendantAxis:
        // In XPath model, attribute nodes do not have children.
        if (context->isAttributeNode())
            return;

        for (Node* n = context->firstChild(); n; n = NodeTraversal::next(*n, context)) {
            if (nodeMatches(evaluationContext, n, DescendantAxis, nodeTest()))
                nodes.append(n);
        }
        return;

    case ParentAxis:
        if (context->isAttributeNode()) {
            Element* n = toAttr(context)->ownerElement();
            if (nodeMatches(evaluationContext, n, ParentAxis, nodeTest()))
                nodes.append(n);
        } else {
            ContainerNode* n = context->parentNode();
            if (n && nodeMatches(evaluationContext, n, ParentAxis, nodeTest()))
                nodes.append(n);
        }
        return;

    case AncestorAxis: {
        Node* n = context;
        if (context->isAttributeNode()) {
            n = toAttr(context)->ownerElement();
            if (nodeMatches(evaluationContext, n, AncestorAxis, nodeTest()))
                nodes.append(n);
        }
        for (n = n->parentNode(); n; n = n->parentNode()) {
            if (nodeMatches(evaluationContext, n, AncestorAxis, nodeTest()))
                nodes.append(n);
        }
        nodes.markSorted(false);
        return;
    }

    case FollowingSiblingAxis:
        if (context->nodeType() == Node::ATTRIBUTE_NODE)
            return;

        for (Node* n = context->nextSibling(); n; n = n->nextSibling()) {
            if (nodeMatches(evaluationContext, n, FollowingSiblingAxis, nodeTest()))
                nodes.append(n);
        }
        return;

    case PrecedingSiblingAxis:
        if (context->nodeType() == Node::ATTRIBUTE_NODE)
            return;

        for (Node* n = context->previousSibling(); n; n = n->previousSibling()) {
            if (nodeMatches(evaluationContext, n, PrecedingSiblingAxis, nodeTest()))
                nodes.append(n);
        }
        nodes.markSorted(false);
        return;

    case FollowingAxis:
        if (context->isAttributeNode()) {
            for (Node* p = NodeTraversal::next(*toAttr(context)->ownerElement()); p; p = NodeTraversal::next(*p)) {
                if (nodeMatches(evaluationContext, p, FollowingAxis, nodeTest()))
                    nodes.append(p);
            }
        } else {
            for (Node* p = context; !isRootDomNode(p); p = p->parentNode()) {
                for (Node* n = p->nextSibling(); n; n = n->nextSibling()) {
                    if (nodeMatches(evaluationContext, n, FollowingAxis, nodeTest()))
                        nodes.append(n);
                    for (Node* c = n->firstChild(); c; c = NodeTraversal::next(*c, n)) {
                        if (nodeMatches(evaluationContext, c, FollowingAxis, nodeTest()))
                            nodes.append(c);
                    }
                }
            }
        }
        return;

    case PrecedingAxis: {
        if (context->isAttributeNode())
            context = toAttr(context)->ownerElement();

        Node* n = context;
        while (ContainerNode* parent = n->parentNode()) {
            for (n = NodeTraversal::previous(*n); n != parent; n = NodeTraversal::previous(*n)) {
                if (nodeMatches(evaluationContext, n, PrecedingAxis, nodeTest()))
                    nodes.append(n);
            }
            n = parent;
        }
        nodes.markSorted(false);
        return;
    }

    case AttributeAxis: {
        if (!context->isElementNode())
            return;

        Element* contextElement = toElement(context);
        // Avoid lazily creating attribute nodes for attributes that we do not
        // need anyway.
        if (nodeTest().kind() == NodeTest::NameTest && nodeTest().data() != starAtom) {
            RefPtrWillBeRawPtr<Node> n = contextElement->getAttributeNodeNS(nodeTest().namespaceURI(), nodeTest().data());
            // In XPath land, namespace nodes are not accessible on the attribute axis.
            if (n && n->namespaceURI() != XMLNSNames::xmlnsNamespaceURI) {
                // Still need to check merged predicates.
                if (nodeMatches(evaluationContext, n.get(), AttributeAxis, nodeTest()))
                    nodes.append(n.release());
            }
            return;
        }

        AttributeCollection attributes = contextElement->attributes();
        AttributeCollection::iterator end = attributes.end();
        for (AttributeCollection::iterator it = attributes.begin(); it != end; ++it) {
            RefPtrWillBeRawPtr<Attr> attr = contextElement->ensureAttr(it->name());
            if (nodeMatches(evaluationContext, attr.get(), AttributeAxis, nodeTest()))
                nodes.append(attr.release());
        }
        return;
    }

    case NamespaceAxis:
        // XPath namespace nodes are not implemented.
        return;

    case SelfAxis:
        if (nodeMatches(evaluationContext, context, SelfAxis, nodeTest()))
            nodes.append(context);
        return;

    case DescendantOrSelfAxis:
        if (nodeMatches(evaluationContext, context, DescendantOrSelfAxis, nodeTest()))
            nodes.append(context);
        // In XPath model, attribute nodes do not have children.
        if (context->isAttributeNode())
            return;

        for (Node* n = context->firstChild(); n; n = NodeTraversal::next(*n, context)) {
            if (nodeMatches(evaluationContext, n, DescendantOrSelfAxis, nodeTest()))
                nodes.append(n);
        }
        return;

    case AncestorOrSelfAxis: {
        if (nodeMatches(evaluationContext, context, AncestorOrSelfAxis, nodeTest()))
            nodes.append(context);
        Node* n = context;
        if (context->isAttributeNode()) {
            n = toAttr(context)->ownerElement();
            if (nodeMatches(evaluationContext, n, AncestorOrSelfAxis, nodeTest()))
                nodes.append(n);
        }
        for (n = n->parentNode(); n; n = n->parentNode()) {
            if (nodeMatches(evaluationContext, n, AncestorOrSelfAxis, nodeTest()))
                nodes.append(n);
        }
        nodes.markSorted(false);
        return;
    }
    }
    ASSERT_NOT_REACHED();
}
예제 #14
0
void Step::nodesInAxis(Node* context, NodeSet& nodes) const
{
    ASSERT(nodes.isEmpty());
    switch (m_axis) {
        case ChildAxis:
            if (context->isAttributeNode()) // In XPath model, attribute nodes do not have children.
                return;

            for (Node* n = context->firstChild(); n; n = n->nextSibling())
                if (nodeMatches(n))
                    nodes.append(n);
            return;
        case DescendantAxis:
            if (context->isAttributeNode()) // In XPath model, attribute nodes do not have children.
                return;

            for (Node* n = context->firstChild(); n; n = n->traverseNextNode(context))
                if (nodeMatches(n))
                    nodes.append(n);
            return;
        case ParentAxis:
            if (context->isAttributeNode()) {
                Node* n = static_cast<Attr*>(context)->ownerElement();
                if (nodeMatches(n))
                    nodes.append(n);
            } else {
                Node* n = context->parentNode();
                if (n && nodeMatches(n))
                    nodes.append(n);
            }
            return;
        case AncestorAxis: {
            Node* n = context;
            if (context->isAttributeNode()) {
                n = static_cast<Attr*>(context)->ownerElement();
                if (nodeMatches(n))
                    nodes.append(n);
            }
            for (n = n->parentNode(); n; n = n->parentNode())
                if (nodeMatches(n))
                    nodes.append(n);
            nodes.reverse();
            return;
        }
        case FollowingSiblingAxis:
            if (context->nodeType() == Node::ATTRIBUTE_NODE ||
                 context->nodeType() == Node::XPATH_NAMESPACE_NODE) 
                return;
            
            for (Node* n = context->nextSibling(); n; n = n->nextSibling())
                if (nodeMatches(n))
                    nodes.append(n);
            return;
        case PrecedingSiblingAxis:
            if (context->nodeType() == Node::ATTRIBUTE_NODE ||
                 context->nodeType() == Node::XPATH_NAMESPACE_NODE)
                return;
            
            for (Node* n = context->previousSibling(); n; n = n->previousSibling())
                if (nodeMatches(n))
                    nodes.append(n);

            nodes.reverse();
            return;
        case FollowingAxis:
            if (context->isAttributeNode()) {
                Node* p = static_cast<Attr*>(context)->ownerElement();
                while ((p = p->traverseNextNode()))
                    if (nodeMatches(p))
                        nodes.append(p);
            } else {
                for (Node* p = context; !isRootDomNode(p); p = p->parentNode()) {
                    for (Node* n = p->nextSibling(); n; n = n->nextSibling()) {
                        if (nodeMatches(n))
                            nodes.append(n);
                        for (Node* c = n->firstChild(); c; c = c->traverseNextNode(n))
                            if (nodeMatches(c))
                                nodes.append(c);
                    }
                }
            }
            return;
        case PrecedingAxis:
            if (context->isAttributeNode())
                context = static_cast<Attr*>(context)->ownerElement();

            for (Node* p = context; !isRootDomNode(p); p = p->parentNode()) {
                for (Node* n = p->previousSibling(); n ; n = n->previousSibling()) {
                    if (nodeMatches(n))
                        nodes.append(n);
                    for (Node* c = n->firstChild(); c; c = c->traverseNextNode(n))
                        if (nodeMatches(c))
                            nodes.append(c);
                }
            }
            nodes.markSorted(false);
            return;
        case AttributeAxis: {
            if (context->nodeType() != Node::ELEMENT_NODE)
                return;

            // Avoid lazily creating attribute nodes for attributes that we do not need anyway.
            if (m_nodeTest.kind() == NodeTest::NameTest && m_nodeTest.data() != "*") {
                RefPtr<Node> n = static_cast<Element*>(context)->getAttributeNodeNS(m_nodeTest.namespaceURI(), m_nodeTest.data());
                if (n && n->namespaceURI() != "http://www.w3.org/2000/xmlns/") // In XPath land, namespace nodes are not accessible on the attribute axis.
                    nodes.append(n.release());
                return;
            }
            
            NamedAttrMap* attrs = context->attributes();
            if (!attrs)
                return;

            for (unsigned long i = 0; i < attrs->length(); ++i) {
                RefPtr<Node> n = attrs->item(i);
                if (nodeMatches(n.get()))
                    nodes.append(n.release());
            }
            return;
        }
        case NamespaceAxis:
            // XPath namespace nodes are not implemented yet.
            return;
        case SelfAxis:
            if (nodeMatches(context))
                nodes.append(context);
            return;
        case DescendantOrSelfAxis:
            if (nodeMatches(context))
                nodes.append(context);
            if (context->isAttributeNode()) // In XPath model, attribute nodes do not have children.
                return;

            for (Node* n = context->firstChild(); n; n = n->traverseNextNode(context))
            if (nodeMatches(n))
                nodes.append(n);
            return;
        case AncestorOrSelfAxis: {
            if (nodeMatches(context))
                nodes.append(context);
            Node* n = context;
            if (context->isAttributeNode()) {
                n = static_cast<Attr*>(context)->ownerElement();
                if (nodeMatches(n))
                    nodes.append(n);
            }
            for (n = n->parentNode(); n; n = n->parentNode())
                if (nodeMatches(n))
                    nodes.append(n);

            nodes.reverse();
            return;
        }
    }
    ASSERT_NOT_REACHED();
}