2006-05-08  Anders Carlsson  <acarlsson@apple.com>

        Reviewed by Darin, Eric and Maciej.

        http://bugzilla.opendarwin.org/show_bug.cgi?id=6638
        Support Mozilla's XPathEvaluator object.
        
        * DerivedSources.make:
        Generate XPath grammar, and JavaScript wrappers.
        
        * WebCore.xcodeproj/project.pbxproj:
        Add new files to project
        
        * bindings/js/kjs_binding.cpp:
        (KJS::):
        (KJS::setDOMException):
        Handle setting XPath exceptions.
        
        * bindings/objc/DOM.mm:
        Just return nil for now when trying to create a wrapper for 
        XPath namespace nodes.

        * bindings/scripts/CodeGeneratorJS.pm:
        Add XPath types. Also add a "CanBeConstructed" extended attribute
        for interfaces that can be constructed directly.
        
        * bridge/mac/WebCorePageBridge.mm:
        (initializeLoggingChannelsIfNecessary):
        Initialize LogXPath channel.
        
        * dom/DOMImplementation.cpp:
        (WebCore::DOMImplementation::hasFeature):
        Support "xpath" version "3.0".
        
        * dom/Document.cpp:
        (WebCore::Document::Document):
        
        (WebCore::Document::importNode):
        Ignore XPath namespace nodes.
        
        (WebCore::Document::createExpression):
        (WebCore::Document::createNSResolver):
        (WebCore::Document::evaluate):
        New functions which call down to a lazily created XPathEvaluator.

        * dom/Document.h:
        Add function declarations.
        
        * dom/Document.idl:
        Add XPath methods.
        
        * dom/Node.h:
        (WebCore::Node::):
        Add XPATH_NAMESPACE_NODE type.
        
        * editing/markup.cpp:
        (WebCore::startMarkup):
        Ignore XPath namespace nodes.
        
        * page/DOMWindow.idl:
        Add constructors for XPathEvaluator and XPathResult.
        
        * platform/Logging.cpp:
        * platform/Logging.h:
        Add XPath log channel

        * xpath: Added.
        * xpath/XPathEvaluator.cpp: Added.
        (WebCore::XPathEvaluator::createExpression):
        (WebCore::XPathEvaluator::createNSResolver):
        (WebCore::XPathEvaluator::evaluate):
        * xpath/XPathEvaluator.h: Added.
        (WebCore::):
        * xpath/XPathEvaluator.idl: Added.
        * xpath/XPathExpression.cpp: Added.
        (WebCore::XPathExpression::createExpression):
        (WebCore::XPathExpression::~XPathExpression):
        (WebCore::XPathExpression::evaluate):
        * xpath/XPathExpression.h: Added.
        * xpath/XPathExpression.idl: Added.
        * xpath/XPathNSResolver.cpp: Added.
        (WebCore::XPathNSResolver::XPathNSResolver):
        (WebCore::XPathNSResolver::lookupNamespaceURI):
        * xpath/XPathNSResolver.h: Added.
        * xpath/XPathNSResolver.idl: Added.
        * xpath/XPathNamespace.cpp: Added.
        (WebCore::XPathNamespace::XPathNamespace):
        (WebCore::XPathNamespace::~XPathNamespace):
        (WebCore::XPathNamespace::ownerDocument):
        (WebCore::XPathNamespace::ownerElement):
        (WebCore::XPathNamespace::prefix):
        (WebCore::XPathNamespace::nodeName):
        (WebCore::XPathNamespace::nodeValue):
        (WebCore::XPathNamespace::namespaceURI):
        (WebCore::XPathNamespace::nodeType):
        * xpath/XPathNamespace.h: Added.
        * xpath/XPathResult.cpp: Added.
        (WebCore::InvalidatingEventListener::InvalidatingEventListener):
        (WebCore::InvalidatingEventListener::handleEvent):
        (WebCore::XPathResult::XPathResult):
        (WebCore::XPathResult::~XPathResult):
        (WebCore::XPathResult::convertTo):
        (WebCore::XPathResult::resultType):
        (WebCore::XPathResult::numberValue):
        (WebCore::XPathResult::stringValue):
        (WebCore::XPathResult::booleanValue):
        (WebCore::XPathResult::singleNodeValue):
        (WebCore::XPathResult::invalidateIteratorState):
        (WebCore::XPathResult::invalidIteratorState):
        (WebCore::XPathResult::snapshotLength):
        (WebCore::XPathResult::iterateNext):
        (WebCore::XPathResult::snapshotItem):
        * xpath/XPathResult.h: Added.
        (WebCore::XPathResult::):
        * xpath/XPathResult.idl: Added.
        * xpath/impl: Added.
        * xpath/impl/XPathExpressionNode.cpp: Added.
        (WebCore::XPath::Expression::evaluationContext):
        (WebCore::XPath::Expression::Expression):
        (WebCore::XPath::Expression::~Expression):
        (WebCore::XPath::Expression::evaluate):
        (WebCore::XPath::Expression::addSubExpression):
        (WebCore::XPath::Expression::optimize):
        (WebCore::XPath::Expression::subExprCount):
        (WebCore::XPath::Expression::subExpr):
        (WebCore::XPath::Expression::isConstant):
        * xpath/impl/XPathExpressionNode.h: Added.
        (WebCore::XPath::EvaluationContext::EvaluationContext):
        * xpath/impl/XPathFunctions.cpp: Added.
        (WebCore::XPath::Interval::Interval):
        (WebCore::XPath::Interval::contains):
        (WebCore::XPath::Interval::asString):
        (WebCore::XPath::Function::setArguments):
        (WebCore::XPath::Function::setName):
        (WebCore::XPath::Function::arg):
        (WebCore::XPath::Function::argCount):
        (WebCore::XPath::Function::name):
        (WebCore::XPath::FunLast::doEvaluate):
        (WebCore::XPath::FunLast::isConstant):
        (WebCore::XPath::FunPosition::doEvaluate):
        (WebCore::XPath::FunPosition::isConstant):
        (WebCore::XPath::FunLocalName::isConstant):
        (WebCore::XPath::FunLocalName::doEvaluate):
        (WebCore::XPath::FunNamespaceURI::isConstant):
        (WebCore::XPath::FunNamespaceURI::doEvaluate):
        (WebCore::XPath::FunName::isConstant):
        (WebCore::XPath::FunName::doEvaluate):
        (WebCore::XPath::FunCount::doEvaluate):
        (WebCore::XPath::FunCount::isConstant):
        (WebCore::XPath::FunString::doEvaluate):
        (WebCore::XPath::FunConcat::doEvaluate):
        (WebCore::XPath::FunStartsWith::doEvaluate):
        (WebCore::XPath::FunContains::doEvaluate):
        (WebCore::XPath::FunSubstringBefore::doEvaluate):
        (WebCore::XPath::FunSubstringAfter::doEvaluate):
        (WebCore::XPath::FunSubstring::doEvaluate):
        (WebCore::XPath::FunStringLength::doEvaluate):
        (WebCore::XPath::FunNormalizeSpace::doEvaluate):
        (WebCore::XPath::FunTranslate::doEvaluate):
        (WebCore::XPath::FunBoolean::doEvaluate):
        (WebCore::XPath::FunNot::doEvaluate):
        (WebCore::XPath::FunTrue::doEvaluate):
        (WebCore::XPath::FunTrue::isConstant):
        (WebCore::XPath::FunLang::doEvaluate):
        (WebCore::XPath::FunLang::isConstant):
        (WebCore::XPath::FunFalse::doEvaluate):
        (WebCore::XPath::FunFalse::isConstant):
        (WebCore::XPath::FunNumber::doEvaluate):
        (WebCore::XPath::FunSum::doEvaluate):
        (WebCore::XPath::FunFloor::doEvaluate):
        (WebCore::XPath::FunCeiling::doEvaluate):
        (WebCore::XPath::FunRound::doEvaluate):
        (WebCore::XPath::FunctionLibrary::self):
        (WebCore::XPath::FunctionLibrary::FunctionLibrary):
        (WebCore::XPath::FunctionLibrary::createFunction):
        * xpath/impl/XPathFunctions.h: Added.
        * xpath/impl/XPathGrammar.y: Added.
        * xpath/impl/XPathParser.cpp: Added.
        (WebCore::XPath::):
        (WebCore::XPath::Parser::charCat):
        (WebCore::XPath::Parser::isAxisName):
        (WebCore::XPath::Parser::isNodeTypeName):
        (WebCore::XPath::Parser::isOperatorContext):
        (WebCore::XPath::Parser::skipWS):
        (WebCore::XPath::Parser::makeTokenAndAdvance):
        (WebCore::XPath::Parser::makeIntTokenAndAdvance):
        (WebCore::XPath::Parser::peekAheadHelper):
        (WebCore::XPath::Parser::peekCurHelper):
        (WebCore::XPath::Parser::lexString):
        (WebCore::XPath::Parser::lexNumber):
        (WebCore::XPath::Parser::lexNCName):
        (WebCore::XPath::Parser::lexQName):
        (WebCore::XPath::Parser::nextTokenInternal):
        (WebCore::XPath::Parser::nextToken):
        (WebCore::XPath::Parser::Parser):
        (WebCore::XPath::Parser::reset):
        (WebCore::XPath::Parser::lex):
        (WebCore::XPath::Parser::parseStatement):
        (WebCore::XPath::Parser::registerParseNode):
        (WebCore::XPath::Parser::unregisterParseNode):
        (WebCore::XPath::Parser::registerPredicateVector):
        (WebCore::XPath::Parser::unregisterPredicateVector):
        (WebCore::XPath::Parser::registerExpressionVector):
        (WebCore::XPath::Parser::unregisterExpressionVector):
        (WebCore::XPath::Parser::registerString):
        (WebCore::XPath::Parser::unregisterString):
        * xpath/impl/XPathParser.h: Added.
        (WebCore::XPath::Token::Token):
        (WebCore::XPath::Parser::):
        (WebCore::XPath::Parser::current):
        * xpath/impl/XPathPath.cpp: Added.
        (WebCore::XPath::Filter::Filter):
        (WebCore::XPath::Filter::~Filter):
        (WebCore::XPath::Filter::doEvaluate):
        (WebCore::XPath::LocationPath::LocationPath):
        (WebCore::XPath::LocationPath::~LocationPath):
        (WebCore::XPath::LocationPath::optimize):
        (WebCore::XPath::LocationPath::doEvaluate):
        (WebCore::XPath::Path::Path):
        (WebCore::XPath::Path::~Path):
        (WebCore::XPath::Path::doEvaluate):
        * xpath/impl/XPathPath.h: Added.
        * xpath/impl/XPathPredicate.cpp: Added.
        (WebCore::XPath::Number::Number):
        (WebCore::XPath::Number::isConstant):
        (WebCore::XPath::Number::doEvaluate):
        (WebCore::XPath::StringExpression::StringExpression):
        (WebCore::XPath::StringExpression::isConstant):
        (WebCore::XPath::StringExpression::doEvaluate):
        (WebCore::XPath::Negative::doEvaluate):
        (WebCore::XPath::NumericOp::NumericOp):
        (WebCore::XPath::NumericOp::doEvaluate):
        (WebCore::XPath::EqTestOp::EqTestOp):
        (WebCore::XPath::EqTestOp::doEvaluate):
        (WebCore::XPath::LogicalOp::LogicalOp):
        (WebCore::XPath::LogicalOp::shortCircuitOn):
        (WebCore::XPath::LogicalOp::isConstant):
        (WebCore::XPath::LogicalOp::doEvaluate):
        (WebCore::XPath::Union::doEvaluate):
        (WebCore::XPath::Predicate::Predicate):
        (WebCore::XPath::Predicate::~Predicate):
        (WebCore::XPath::Predicate::evaluate):
        (WebCore::XPath::Predicate::optimize):
        * xpath/impl/XPathPredicate.h: Added.
        (WebCore::XPath::NumericOp::):
        (WebCore::XPath::EqTestOp::):
        (WebCore::XPath::LogicalOp::):
        * xpath/impl/XPathStep.cpp: Added.
        (WebCore::XPath::Step::axisAsString):
        (WebCore::XPath::Step::Step):
        (WebCore::XPath::Step::~Step):
        (WebCore::XPath::Step::evaluate):
        (WebCore::XPath::Step::nodesInAxis):
        (WebCore::XPath::Step::nodeTestMatches):
        (WebCore::XPath::Step::optimize):
        (WebCore::XPath::Step::namespaceFromNodetest):
        (WebCore::XPath::Step::primaryNodeType):
        * xpath/impl/XPathStep.h: Added.
        (WebCore::XPath::Step::):
        * xpath/impl/XPathUtil.cpp: Added.
        (WebCore::XPath::isRootDomNode):
        (WebCore::XPath::stringValue):
        (WebCore::XPath::isValidContextNode):
        * xpath/impl/XPathUtil.h: Added.
        * xpath/impl/XPathValue.cpp: Added.
        (WebCore::XPath::Value::Value):
        (WebCore::XPath::Value::type):
        (WebCore::XPath::Value::isNodeVector):
        (WebCore::XPath::Value::isBoolean):
        (WebCore::XPath::Value::isNumber):
        (WebCore::XPath::Value::isString):
        (WebCore::XPath::Value::toNodeVector):
        (WebCore::XPath::Value::toBoolean):
        (WebCore::XPath::Value::toNumber):
        (WebCore::XPath::Value::toString):
        * xpath/impl/XPathValue.h: Added.
        (WebCore::XPath::Value::):
        * xpath/impl/XPathVariableReference.cpp: Added.
        (WebCore::XPath::VariableReference::VariableReference):
        (WebCore::XPath::VariableReference::isConstant):
        (WebCore::XPath::VariableReference::doEvaluate):
        * xpath/impl/XPathVariableReference.h: Added.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@14234 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/WebCore/xpath/impl/XPathStep.cpp b/WebCore/xpath/impl/XPathStep.cpp
new file mode 100644
index 0000000..05c8d15
--- /dev/null
+++ b/WebCore/xpath/impl/XPathStep.cpp
@@ -0,0 +1,373 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "config.h"
+
+#if XPATH_SUPPORT
+
+#include "XPathStep.h"
+
+#include "Logging.h"
+#include "Document.h"
+#include "NamedAttrMap.h"
+#include "Node.h"
+#include "Text.h"
+#include "XPathNSResolver.h"
+
+namespace WebCore {
+namespace XPath {
+
+String Step::axisAsString(AxisType axis)
+{
+    switch (axis) {
+        case AncestorAxis: return "ancestor";
+        case AncestorOrSelfAxis: return "ancestor-or-self";
+        case AttributeAxis: return "attribute";
+        case ChildAxis: return "child";
+        case DescendantAxis: return "descendant";
+        case DescendantOrSelfAxis: return "descendant-or-self";
+        case FollowingAxis: return "following";
+        case FollowingSiblingAxis: return "following-sibling";
+        case NamespaceAxis: return "namespace";
+        case ParentAxis: return "parent";
+        case PrecedingAxis: return "preceding";
+        case PrecedingSiblingAxis: return "preceding-sibling";
+        case SelfAxis: return "self";
+    }
+    return String();
+}
+
+Step::Step()
+{
+}
+
+Step::Step(AxisType axis, const String& nodeTest, const Vector<Predicate*>& predicates)
+    : m_axis(axis),
+    m_nodeTest(nodeTest),
+    m_predicates(predicates)
+{
+}
+
+Step::~Step()
+{
+    deleteAllValues(m_predicates);
+}
+
+NodeVector Step::evaluate(Node* context) const
+{
+    LOG(XPath, "Evaluating step, axis='%s', nodetest='%s', %u predicates",
+            axisAsString(m_axis).ascii(), m_nodeTest.ascii(), m_predicates.size());
+    if (context->nodeType() == Node::ELEMENT_NODE)
+        LOG(XPath, "Context node is an element called %s", context->nodeName().ascii());
+    else if (context->nodeType() == Node::ATTRIBUTE_NODE)
+        LOG(XPath, "Context node is an attribute called %s with value %s", 
+               context->nodeName().ascii(), 
+               context->nodeValue().ascii());
+    else
+        LOG(XPath, "Context node is of unknown type %d", context->nodeType());
+
+    NodeVector inNodes = nodesInAxis(context), outNodes;
+    LOG(XPath, "Axis %s matches %d nodes.", axisAsString(m_axis).ascii(), inNodes.size());
+
+    inNodes = nodeTestMatches(inNodes);
+    LOG(XPath, "Nodetest %s trims this number to %d", m_nodeTest.ascii(), inNodes.size());
+    
+    outNodes = inNodes;
+    for (unsigned i = 0; i < m_predicates.size(); i++) {
+        Predicate* predicate = m_predicates[i];
+
+        outNodes.clear();
+        Expression::evaluationContext().size = inNodes.size();
+        Expression::evaluationContext().position = 1;
+        for (unsigned j = 0; j < inNodes.size(); j++) {
+            Node* node = inNodes[j].get();
+
+            Expression::evaluationContext().node = node;
+            EvaluationContext backupCtx = Expression::evaluationContext();
+            if (predicate->evaluate())
+                outNodes.append(node);
+
+            Expression::evaluationContext() = backupCtx;
+            ++Expression::evaluationContext().position;
+        }
+
+        LOG(XPath, "\tPredicate trims this number to %d", outNodes.size());
+
+        inNodes = outNodes;
+    }
+    return outNodes;
+}
+
+NodeVector Step::nodesInAxis(Node* context) const
+{
+    NodeVector nodes;
+    switch (m_axis) {
+        case ChildAxis:
+            for (Node* n = context->firstChild(); n; n = n->nextSibling())
+                nodes.append(n);
+            return nodes;
+        case DescendantAxis: 
+            for (Node* n = context->firstChild(); n; n = n->traverseNextNode(context))
+                nodes.append(n);
+            return nodes;
+        case ParentAxis:
+            nodes.append(context->parentNode());
+            return nodes;
+        case AncestorAxis:
+            for (Node* n = context->parentNode(); n; n = n->parentNode())
+                nodes.append(n);
+            return nodes;
+        case FollowingSiblingAxis:
+            if (context->nodeType() == Node::ATTRIBUTE_NODE ||
+                 context->nodeType() == Node::XPATH_NAMESPACE_NODE) 
+                return NodeVector();
+            
+            for (Node* n = context->nextSibling(); n; n = n->nextSibling())
+                nodes.append(n);
+            return nodes;
+        case PrecedingSiblingAxis:
+            if (context->nodeType() == Node::ATTRIBUTE_NODE ||
+                 context->nodeType() == Node::XPATH_NAMESPACE_NODE)
+                return NodeVector();
+            
+            for (Node* n = context->previousSibling(); n; n = n->previousSibling())
+                nodes.append(n);
+            return nodes;
+        case FollowingAxis: 
+            for (Node *p = context; !isRootDomNode(p); p = p->parentNode()) {
+                for (Node* n = p->nextSibling(); n; n = n->nextSibling()) {
+                    nodes.append(n);
+                    for (Node* c = n->firstChild(); c; c = c->traverseNextNode(n))
+                        nodes.append(c);
+                }
+            }
+            return nodes;
+        case PrecedingAxis:
+            for (Node* p = context; !isRootDomNode(p); p = p->parentNode()) {
+                for (Node* n = p->previousSibling(); n ; n = n->previousSibling()) {
+                    nodes.append(n);
+                    for (Node* c = n->firstChild(); c; c = c->traverseNextNode(n))
+                        nodes.append(c);
+                }
+            }
+            return nodes;
+        case AttributeAxis: {
+            if (context->nodeType() != Node::ELEMENT_NODE)
+                return NodeVector();
+
+            NamedAttrMap* attrs = context->attributes();
+            if (!attrs) {
+                LOG(XPath, "Node::attributes() returned NULL!");
+                return nodes;
+            }
+
+            for (unsigned long i = 0; i < attrs->length(); ++i) 
+                nodes.append (attrs->item(i));
+            return nodes;
+        }
+        case NamespaceAxis: {
+            if (context->nodeType() != Node::ELEMENT_NODE)
+                return NodeVector();
+
+            bool foundXmlNsNode = false;
+            for (Node* node = context; node; node = node->parentNode()) {
+                NamedAttrMap* attrs = node->attributes();
+                if (!attrs) {
+                    LOG(XPath, "Node::attributes() returned NULL!");
+
+                    continue;
+                }
+
+                for (unsigned long i = 0; i < attrs->length(); ++i) {
+                    Node* n = attrs->item(i).get();
+                    if (n->nodeName().startsWith("xmlns:")) {
+                        nodes.append(n);
+                    } else if (n->nodeName() == "xmlns" &&
+                               !foundXmlNsNode) {
+                        foundXmlNsNode = true;
+                        if (!n->nodeValue().isEmpty())
+                            nodes.append(n);
+                    }
+                }
+            }
+            return nodes;
+        }
+        case SelfAxis:
+            nodes.append(context);
+            return nodes;
+        case DescendantOrSelfAxis:
+            nodes.append(context);
+            for (Node* n = context->firstChild(); n; n = n->traverseNextNode(context))
+                nodes.append(n);
+            return nodes;
+        case AncestorOrSelfAxis:
+            nodes.append(context);
+            for (Node* n = context->parentNode(); n; n = n->parentNode())
+                nodes.append(n);
+            return nodes;
+    }
+
+    return NodeVector();
+}
+
+
+NodeVector Step::nodeTestMatches(const NodeVector& nodes) const
+{
+    String ns = namespaceFromNodetest(m_nodeTest);
+    NodeVector matches;
+    if (m_nodeTest == "*") {
+        for (unsigned i = 0; i < nodes.size(); i++) {
+            Node* node = nodes[i].get();
+            if (node->nodeType() == primaryNodeType(m_axis)) {
+                if (ns.isEmpty() ||
+                     node->namespaceURI() == ns) {
+                    matches.append(node);
+                }
+            }
+        }
+        return nodes;
+    } else if (m_nodeTest == "text()") {
+        for (unsigned i = 0; i < nodes.size(); i++) {
+            Node* node = nodes[i].get();
+            if (node->nodeType() == Node::TEXT_NODE ||
+                node->nodeType() == Node::CDATA_SECTION_NODE) 
+                matches.append(node);
+        }
+        return matches;
+    } else if (m_nodeTest == "comment()") {
+        for (unsigned i = 0; i < nodes.size(); i++) {
+            Node* node = nodes[i].get();
+            if (node->nodeType() == Node::COMMENT_NODE)
+                matches.append(node);
+        }
+        return matches;
+    } else if (m_nodeTest.startsWith("processing-instruction")) {
+        String param;
+
+        const int space = m_nodeTest.find(' ');
+        if (space > -1)
+            param = m_nodeTest.deprecatedString().mid(space + 1);
+
+        for (unsigned i = 0; i < nodes.size(); i++) {
+            Node* node = nodes[i].get();
+
+            if (node->nodeType() == Node::PROCESSING_INSTRUCTION_NODE &&
+                (param.isEmpty() || node->nodeName() == param))
+                    matches.append(node);
+        }    
+        return matches;
+    } else if (m_nodeTest == "node()")
+        return nodes;
+    else {
+        String prefix, localName;
+
+        const int colon = m_nodeTest.find(':');
+        if (colon > -1) {
+            prefix = m_nodeTest.left(colon);
+            localName = m_nodeTest.deprecatedString().mid(colon + 1);
+        } else {
+            localName = m_nodeTest;
+        }
+
+        if (!prefix.isEmpty() &&
+            Expression::evaluationContext().resolver->lookupNamespaceURI(prefix).isEmpty()) {
+                /* FIXME: Throw NAMESPACE_ERR exception */
+        }
+
+        if (m_axis == AttributeAxis) {
+            // In XPath land, namespace nodes are not accessible
+            // on the attribute axis.
+            if (localName == "xmlns")
+                return matches;
+
+            for (unsigned i = 0; i < nodes.size(); i++) {
+                Node* node = nodes[i].get();
+                
+                if (node->nodeName() == localName) {
+                    matches.append(node);
+                    break; // There can only be one.
+                }
+            }
+
+            return matches;
+        } else if (m_axis == NamespaceAxis) {
+            LOG(XPath, "Node test %s on axis %s is not implemented yet.",
+                m_nodeTest.ascii(), axisAsString(m_axis).ascii());
+        } else {
+            for (unsigned i = 0; i < nodes.size(); i++) {
+                Node* node = nodes[i].get();
+ 
+                // We use tagQName here because we don't want the element name in uppercase 
+                // like we get with HTML elements.
+                if (node->nodeType() == Node::ELEMENT_NODE &&
+                    static_cast<Element*>(node)->tagQName().toString() == localName) {
+                    matches.append(node);
+                }
+            }
+
+            return matches;
+        }
+    }
+    
+    LOG(XPath, "Node test %s on axis %s is not implemented yet.",
+        m_nodeTest.ascii(), axisAsString(m_axis).ascii());
+
+    return matches;
+}
+
+void Step::optimize()
+{
+    for (unsigned i = 0; i < m_predicates.size(); i++)
+        m_predicates[i]->optimize();
+}
+
+String Step::namespaceFromNodetest(const String& nodeTest) const
+{
+    int i = nodeTest.find(':');
+    if (i == -1)
+        return String();
+
+    String prefix(nodeTest.left(i));
+    
+    Node* ctxNode = Expression::evaluationContext().node.get();
+    return ctxNode->lookupNamespaceURI(prefix);
+}
+
+Node::NodeType Step::primaryNodeType(AxisType axis) const
+{
+    switch (axis) {
+        case AttributeAxis:
+            return Node::ATTRIBUTE_NODE;
+        case NamespaceAxis:
+            return Node::XPATH_NAMESPACE_NODE;
+        default:
+            return Node::ELEMENT_NODE;
+    }
+}
+
+}
+}
+
+#endif // XPATH_SUPPORT