dbertoni 01/10/24 08:44:51
Modified: c/src/XPath XPath.cpp XPath.hpp
Log:
XPath/SimpleNodeLocator integration.
Revision Changes Path
1.63 +2317 -4 xml-xalan/c/src/XPath/XPath.cpp
Index: XPath.cpp
===================================================================
RCS file: /home/cvs/xml-xalan/c/src/XPath/XPath.cpp,v
retrieving revision 1.62
retrieving revision 1.63
diff -u -r1.62 -r1.63
--- XPath.cpp 2001/09/14 20:06:26 1.62
+++ XPath.cpp 2001/10/24 15:44:51 1.63
@@ -71,15 +71,22 @@
+#include <XalanDOM/XalanNamedNodeMap.hpp>
+
+
+
#include <PlatformSupport/DoubleSupport.hpp>
#include <PlatformSupport/PrefixResolver.hpp>
+#include <DOMSupport/DOMServices.hpp>
+
+
+
#include "FoundIndex.hpp"
#include "MutableNodeRefList.hpp"
#include "XalanQNameByReference.hpp"
-#include "SimpleNodeLocator.hpp"
#include "XLocator.hpp"
#include "XPathException.hpp"
#include "XObject.hpp"
@@ -88,6 +95,10 @@
+const XalanDOMString XPath::s_emptyString;
+
+
+
XPath::XPath(const Locator* theLocator) :
m_expression(),
m_locator(theLocator),
@@ -302,7 +313,7 @@
{
const int nextOpPos =
m_expression.getNextOpCodePosition(opPos);
- score = SimpleNodeLocator::locationPathPattern(*this,
executionContext, *context, opPos);
+ score = locationPathPattern(executionContext, *context, opPos);
if(score == eMatchScoreNone)
{
@@ -954,7 +965,7 @@
{
assert(context != 0);
- return SimpleNodeLocator::locationPath(*this, executionContext,
*context, opPos);
+ return locationPath(executionContext, *context, opPos);
}
@@ -968,7 +979,7 @@
assert(context != 0);
const eMatchScore result =
- SimpleNodeLocator::locationPathPattern(*this, executionContext,
*context, opPos);
+ locationPathPattern(executionContext, *context, opPos);
return
executionContext.getXObjectFactory().createNumber(getMatchScoreValue(result));
}
@@ -1112,6 +1123,2308 @@
return function(context, funcID, args, executionContext);
}
+}
+
+
+
+const XObjectPtr
+XPath::locationPath(
+ XPathExecutionContext& executionContext,
+ XalanNode& context,
+ int opPos) const
+{
+ typedef XPathExecutionContext::BorrowReturnMutableNodeRefList
BorrowReturnMutableNodeRefList;
+
+ BorrowReturnMutableNodeRefList mnl(executionContext);
+
+ step(executionContext, &context, opPos + 2, *mnl.get());
+
+ return executionContext.getXObjectFactory().createNodeSet(mnl);
+}
+
+
+
+XPath::eMatchScore
+XPath::locationPathPattern(
+ XPathExecutionContext& executionContext,
+ XalanNode& context,
+ int opPos) const
+{
+ eMatchScore score = eMatchScoreNone;
+
+ stepPattern(executionContext, &context, opPos + 2, score);
+
+ return score;
+}
+
+
+
+void
+XPath::step(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ MutableNodeRefList& queryResults) const
+{
+ const XPathExpression& currentExpression = getExpression();
+
+ // int endStep = xpath.getNextOpPos(opPos);
+ const int stepType =
+ currentExpression.getOpCodeMapValue(opPos);
+
+ int argLen = 0;
+
+ typedef XPathExecutionContext::BorrowReturnMutableNodeRefList
BorrowReturnMutableNodeRefList;
+
+ BorrowReturnMutableNodeRefList subQueryResults(executionContext);
+
+ bool shouldReorder = false;
+ bool continueStepRecursion = true;
+
+ switch(stepType)
+ {
+ case XPathExpression::eOP_VARIABLE:
+ case XPathExpression::eOP_EXTFUNCTION:
+ case XPathExpression::eOP_FUNCTION:
+ case XPathExpression::eOP_GROUP:
+ argLen = findNodeSet(executionContext, context, opPos,
stepType, *subQueryResults);
+ break;
+
+ case XPathExpression::eFROM_ROOT:
+ argLen = findRoot(executionContext, context, opPos, stepType,
*subQueryResults);
+ break;
+
+ case XPathExpression::eFROM_PARENT:
+ argLen = findParent(executionContext, context, opPos, stepType,
*subQueryResults);
+ break;
+
+ case XPathExpression::eFROM_SELF:
+ argLen = findSelf(executionContext, context, opPos, stepType,
*subQueryResults);
+ break;
+
+ case XPathExpression::eFROM_ANCESTORS:
+ argLen = findAncestors(executionContext, context, opPos,
stepType, *subQueryResults);
+ shouldReorder = true;
+ break;
+
+ case XPathExpression::eFROM_ANCESTORS_OR_SELF:
+ argLen = findAncestorsOrSelf(executionContext, context, opPos,
stepType, *subQueryResults);
+ shouldReorder = true;
+ break;
+
+ case XPathExpression::eMATCH_ATTRIBUTE:
+ continueStepRecursion = false;
+ // fall-through on purpose.
+
+ case XPathExpression::eFROM_ATTRIBUTES:
+ argLen = findAttributes(executionContext, context, opPos,
stepType, *subQueryResults);
+ break;
+
+ case XPathExpression::eMATCH_ANY_ANCESTOR:
+ case XPathExpression::eMATCH_IMMEDIATE_ANCESTOR:
+ case XPathExpression::eMATCH_ANY_ANCESTOR_WITH_PREDICATE:
+ continueStepRecursion = false;
+ // fall-through on purpose.
+
+ case XPathExpression::eFROM_CHILDREN:
+ argLen = findChildren(executionContext, context, opPos,
stepType, *subQueryResults);
+ break;
+
+ case XPathExpression::eFROM_DESCENDANTS:
+ case XPathExpression::eFROM_DESCENDANTS_OR_SELF:
+ argLen = findDescendants(executionContext, context, opPos,
stepType, *subQueryResults);
+ break;
+
+ case XPathExpression::eFROM_FOLLOWING:
+ argLen = findFollowing(executionContext, context, opPos,
stepType, *subQueryResults);
+ break;
+
+ case XPathExpression::eFROM_FOLLOWING_SIBLINGS:
+ argLen = findFollowingSiblings(executionContext, context,
opPos, stepType, *subQueryResults);
+ break;
+
+ case XPathExpression::eFROM_PRECEDING:
+ argLen = findPreceeding(executionContext, context, opPos,
stepType, *subQueryResults);
+ shouldReorder = true;
+ break;
+
+ case XPathExpression::eFROM_PRECEDING_SIBLINGS:
+ argLen = findPreceedingSiblings(executionContext, context,
opPos, stepType, *subQueryResults);
+ shouldReorder = true;
+ break;
+
+ case XPathExpression::eFROM_NAMESPACE:
+ argLen = findNamespace(executionContext, context, opPos,
stepType, *subQueryResults);
+ break;
+
+ default:
+ argLen = findNodesOnUnknownAxis(executionContext, context,
opPos, stepType, *subQueryResults);
+ break;
+ }
+
+ // Push and pop the PrefixResolver...
+ XPathExecutionContext::ContextNodeListSetAndRestore
theSetAndRestore(
+
executionContext,
+
*subQueryResults);
+
+ opPos += argLen;
+
+ int nextStepType =
currentExpression.getOpCodeMapValue(opPos);
+
+ if(XPathExpression::eOP_PREDICATE == nextStepType)
+ {
+ predicates(executionContext,
+ context,
+ opPos,
+ *subQueryResults,
+ opPos);
+
+ nextStepType = currentExpression.getOpCodeMapValue(opPos);
+ }
+
+ if(XPathExpression::eENDOP != nextStepType && continueStepRecursion ==
true)
+ {
+ const NodeRefListBase::size_type nContexts =
subQueryResults->getLength();
+
+ for(NodeRefListBase::size_type i = 0; i < nContexts; i++)
+ {
+ XalanNode* const node = subQueryResults->item(i);
+
+ if(0 != node)
+ {
+ BorrowReturnMutableNodeRefList
mnl(executionContext);
+
+ step(executionContext, node, opPos, *mnl);
+
+ if (mnl->getLength() > 0)
+ {
+ if(queryResults.getLength() == 0)
+ {
+ queryResults = *mnl;
+ }
+ else
+ {
+
queryResults.addNodesInDocOrder(*mnl, executionContext);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (shouldReorder == true)
+ {
+ queryResults.addNodesInDocOrder(*subQueryResults,
executionContext);
+ }
+ else
+ {
+ queryResults = *subQueryResults;
+ }
+ }
+}
+
+
+
+XalanNode*
+XPath::stepPattern(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ eMatchScore& scoreHolder) const
+{
+ const XPathExpression& currentExpression = getExpression();
+
+ const int endStep =
currentExpression.getNextOpCodePosition(opPos);
+ int nextStepType =
currentExpression.getOpCodeMapValue(endStep);
+
+ if(XPathExpression::eENDOP != nextStepType)
+ {
+ // Continue step via recursion...
+ context = stepPattern(
+ executionContext,
+ context,
+ endStep,
+ scoreHolder);
+
+ if(0 == context)
+ {
+ scoreHolder = eMatchScoreNone;
+
+ }
+
+ if (scoreHolder == eMatchScoreNone)
+ {
+ // !!!!!!!!!!!!! Big ugly return here
!!!!!!!!!!!!!!!!!!!
+ return 0;
+ }
+
+ scoreHolder = eMatchScoreOther;
+
+ if (nextStepType !=
XPathExpression::eMATCH_ANY_ANCESTOR_WITH_FUNCTION_CALL)
+ {
+ context = DOMServices::getParentOfNode(*context);
+ }
+
+ if(0 == context)
+ {
+ // !!!!!!!!!!!!! Big ugly return here
!!!!!!!!!!!!!!!!!!!
+ return 0;
+ }
+ }
+
+ assert(context != 0);
+
+ int argLen = 0;
+
+ eMatchScore score = eMatchScoreNone;
+
+ const int startOpPos = opPos;
+ const int stepType = currentExpression.getOpCodeMapValue(opPos);
+
+ switch(stepType)
+ {
+ case XPathExpression::eMATCH_ANY_ANCESTOR_WITH_FUNCTION_CALL:
+ score = scoreHolder;
+ break;
+
+ case XPathExpression::eOP_FUNCTION:
+ {
+ argLen =
currentExpression.getOpCodeLengthFromOpMap(opPos);
+
+ const XObjectPtr
obj(executeMore(context, opPos, executionContext));
+ assert(obj.get() != 0);
+
+ const NodeRefListBase& nl =
obj->nodeset();
+
+ const NodeRefListBase::size_type len =
nl.getLength();
+
+ if (nextStepType ==
XPathExpression::eMATCH_ANY_ANCESTOR_WITH_FUNCTION_CALL)
+ {
+ bool fFound = false;
+
+ while(context != 0 && fFound == false)
+ {
+ for(NodeRefListBase::size_type i = 0; i
< len; i++)
+ {
+ XalanNode* const n =
nl.item(i);
+
+ if(n == context)
+ {
+ score =
eMatchScoreOther;
+
+ context = n;
+
+ fFound = true;
+
+ break;
+ }
+ }
+
+ context =
DOMServices::getParentOfNode(*context);
+ }
+ }
+ else
+ {
+ for(NodeRefListBase::size_type i = 0; i < len;
i++)
+ {
+ XalanNode* const n = nl.item(i);
+
+ if(n == context)
+ {
+ score = eMatchScoreOther;
+
+ context = n;
+
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case XPathExpression::eFROM_ROOT:
+ {
+ // $$ ToDO: Can we reduce this to some call on the
+ // XPathExpression interface?
+ argLen =
+ currentExpression.getOpCodeMapValue(opPos +
XPathExpression::s_opCodeMapLengthIndex + 1) - 3;
+
+ opPos += 3;
+
+ const XalanNode::NodeType nodeType =
context->getNodeType();
+
+ if (nodeType == XalanNode::DOCUMENT_NODE ||
+ nodeType == XalanNode::DOCUMENT_FRAGMENT_NODE)
+ {
+ score = eMatchScoreOther;
+ }
+ else
+ {
+ const int prevPos =
currentExpression.getNextOpCodePosition(startOpPos);
+ const int prevStepType =
currentExpression.getOpCodeMapValue(prevPos);
+
+ if (eMatchScoreNone == score &&
+ (prevStepType ==
XPathExpression::eMATCH_ANY_ANCESTOR ||
+ prevStepType ==
XPathExpression::eMATCH_ANY_ANCESTOR_WITH_PREDICATE))
+ {
+ const NodeTester theTester(
+ *this,
+
executionContext,
+ opPos,
+ argLen,
+
stepType);
+
+ while(0 != context)
+ {
+ score =
+ theTester(*context,
context->getNodeType());
+ assert(score ==
nodeTest(executionContext, context, context->getNodeType(), opPos, argLen,
stepType));
+
+ if(eMatchScoreNone != score)
+ break;
+
+ context =
DOMServices::getParentOfNode(*context);
+ }
+ }
+ }
+ }
+ break;
+
+ case XPathExpression::eMATCH_ATTRIBUTE:
+ {
+ // $$ ToDO: Can we reduce this to some call on the
+ // XPathExpression interface?
+ argLen =
+ currentExpression.getOpCodeMapValue(opPos +
XPathExpression::s_opCodeMapLengthIndex + 1) - 3;
+
+ opPos += 3;
+
+ score = NodeTester(
+ *this,
+ executionContext,
+ opPos,
+ argLen,
+
XPathExpression::eFROM_ATTRIBUTES)(*context, context->getNodeType());
+
+ assert(score == nodeTest(
+ executionContext,
+ context,
+ context->getNodeType(),
+ opPos,
+ argLen,
+
XPathExpression::eFROM_ATTRIBUTES));
+ }
+ break;
+
+ case XPathExpression::eMATCH_ANY_ANCESTOR:
+ case XPathExpression::eMATCH_ANY_ANCESTOR_WITH_PREDICATE:
+ {
+ // $$ ToDO: Can we reduce this to some call on the
+ // XPathExpression interface?
+ argLen =
+
currentExpression.getOpCodeMapValue(opPos +
XPathExpression::s_opCodeMapLengthIndex + 1) - 3;
+
+ XalanNode::NodeType nodeType =
context->getNodeType();
+
+ if(nodeType != XalanNode::ATTRIBUTE_NODE)
+ {
+ opPos += 3;
+
+ const NodeTester theTester(
+ *this,
+
executionContext,
+ opPos,
+ argLen,
+
stepType);
+
+ for(;;)
+ {
+ score = theTester(*context, nodeType);
+ assert(score ==
nodeTest(executionContext, context, nodeType, opPos, argLen, stepType));
+
+ if(eMatchScoreNone != score)
+ break;
+
+ context =
DOMServices::getParentOfNode(*context);
+
+ if (context == 0)
+ break;
+
+ nodeType = context->getNodeType();
+ }
+ }
+ }
+ break;
+
+ case XPathExpression::eMATCH_IMMEDIATE_ANCESTOR:
+ {
+ // $$ ToDO: Can we reduce this to some call on the
+ // XPathExpression interface?
+ argLen =
+ currentExpression.getOpCodeMapValue(opPos +
XPathExpression::s_opCodeMapLengthIndex + 1) - 3;
+
+ const XalanNode::NodeType nodeType =
context->getNodeType();
+
+ if(nodeType != XalanNode::ATTRIBUTE_NODE)
+ {
+ opPos += 3;
+
+ score = NodeTester(
+ *this,
+
executionContext,
+ opPos,
+ argLen,
+
XPathExpression::eMATCH_IMMEDIATE_ANCESTOR)(*context, nodeType);
+
+ assert(score == nodeTest(
+
executionContext,
+ context,
+ nodeType,
+ opPos,
+ argLen,
+
XPathExpression::eMATCH_IMMEDIATE_ANCESTOR));
+ }
+ }
+ break;
+
+ default:
+ executionContext.error(TranscodeFromLocalCodePage("unknown
match operation!"), context, getLocator());
+ break;
+ }
+
+ opPos += argLen;
+
+ nextStepType = currentExpression.getOpCodeMapValue(opPos);
+
+ if(score != eMatchScoreNone && XPathExpression::eOP_PREDICATE ==
nextStepType)
+ {
+ score = eMatchScoreOther;
+
+ // Execute the xpath.predicates, but if we have an index, then
we have
+ // to start over and do a search from the parent. It would be
nice
+ // if I could sense this condition earlier...
+ try
+ {
+ executionContext.setThrowFoundIndex(true);
+
+ while(XPathExpression::eOP_PREDICATE == nextStepType)
+ {
+ const XObjectPtr
pred(predicate(context, opPos, executionContext));
+ assert(pred.get() != 0);
+
+ if(XObject::eTypeNumber == pred->getType())
+ {
+ score =
handleFoundIndex(executionContext, context, startOpPos);
+ }
+ else if(pred->boolean() == false)
+ {
+ score = eMatchScoreNone;
+
+ break;
+ }
+
+ opPos =
currentExpression.getNextOpCodePosition(opPos);
+ nextStepType =
currentExpression.getOpCodeMapValue(opPos);
+ }
+
+ executionContext.setThrowFoundIndex(false);
+ }
+ catch(const FoundIndex&)
+ {
+ score = handleFoundIndex(executionContext, context,
startOpPos);
+ }
+ }
+
+ if (scoreHolder == eMatchScoreNone ||
+ score == eMatchScoreNone)
+ {
+ scoreHolder = score;
+ }
+
+ return score == eMatchScoreNone ? 0 : context;
+}
+
+
+
+XPath::eMatchScore
+XPath::handleFoundIndex(
+ XPathExecutionContext& executionContext,
+ XalanNode* localContext,
+ int startOpPos)
const
+{
+ // We have an index somewhere in our pattern. So, we have
+ // to do a full search for our step, using the parent as
+ // localContext, then see if the current localContext is found in the
+ // node set. Seems crazy, but, so far, it seems like the
+ // easiest way.
+ executionContext.setThrowFoundIndex(false);
+
+ XalanNode* const parentContext =
+ DOMServices::getParentOfNode(*localContext);
+
+ if (parentContext == 0)
+ {
+ return eMatchScoreNone;
+ }
+ else
+ {
+ typedef XPathExecutionContext::BorrowReturnMutableNodeRefList
BorrowReturnMutableNodeRefList;
+
+ BorrowReturnMutableNodeRefList mnl(executionContext);
+
+ step(executionContext, parentContext, startOpPos, *mnl);
+
+ if (mnl->indexOf(localContext) == MutableNodeRefList::npos)
+ {
+ return eMatchScoreNone;
+ }
+ else
+ {
+ return eMatchScoreOther;
+ }
+ }
+}
+
+
+
+int
+XPath::findNodeSet(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int /* stepType */,
+ MutableNodeRefList& subQueryResults) const
+{
+ const XPathExpression& currentExpression = getExpression();
+
+ const XObjectPtr obj(executeMore(context, opPos,
executionContext));
+
+ const NodeRefListBase& nl = obj->nodeset();
+
+ subQueryResults.addNodes(nl);
+
+ return currentExpression.getOpCodeLengthFromOpMap(opPos);
+}
+
+
+
+int
+XPath::findRoot(
+ XPathExecutionContext& /* executionContext */,
+ XalanNode* context,
+ int opPos,
+ int /* stepType */,
+ MutableNodeRefList& subQueryResults) const
+{
+ const XPathExpression& currentExpression = getExpression();
+
+ // $$ ToDO: Can we reduce this to some call on the
+ // XPathExpression interface?
+ const int argLen =
+ currentExpression.getOpCodeMapValue(opPos +
XPathExpression::s_opCodeMapLengthIndex + 1) - 3;
+
+ XalanNode* const docContext = XalanNode::DOCUMENT_NODE ==
context->getNodeType() ?
+ context
:
+
context->getOwnerDocument();
+ assert(docContext != 0);
+
+ subQueryResults.addNode(docContext);
+
+ return argLen + 3;
+}
+
+
+
+int
+XPath::findParent(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const
+{
+ assert(context != 0);
+
+ const XPathExpression& currentExpression = getExpression();
+
+ // $$ ToDO: Can we reduce this to some call on the
+ // XPathExpression interface?
+ const int argLen =
+ currentExpression.getOpCodeMapValue(opPos +
XPathExpression::s_opCodeMapLengthIndex + 1) - 3;
+
+ XalanNode* const theParent =
DOMServices::getParentOfNode(*context);
+
+ if(0 != theParent)
+ {
+ if(argLen > 0)
+ {
+ opPos += 3;
+
+ const NodeTester theTester(
+ *this,
+ executionContext,
+ opPos,
+ argLen,
+ stepType);
+
+ const eMatchScore score = theTester(*theParent,
theParent->getNodeType());
+ assert(score == nodeTest(executionContext, theParent,
theParent->getNodeType(), opPos, argLen, stepType));
+
+ if(eMatchScoreNone != score)
+ {
+ subQueryResults.addNode(theParent);
+ }
+ }
+ else
+ {
+ subQueryResults.addNode(theParent);
+ }
+ }
+
+ subQueryResults.setDocumentOrder();
+
+ return argLen + 3;
+}
+
+
+
+int
+XPath::findSelf(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const
+{
+ assert(context != 0);
+
+ const XPathExpression& currentExpression = getExpression();
+
+ // $$ ToDO: Can we reduce this to some call on the
+ // XPathExpression interface?
+ const int argLen =
+ currentExpression.getOpCodeMapValue(opPos +
XPathExpression::s_opCodeMapLengthIndex + 1) - 3;
+
+ if(argLen == 0)
+ {
+ subQueryResults.addNode(context);
+ }
+ else
+ {
+ opPos += 3;
+
+ const NodeTester theTester(
+ *this,
+ executionContext,
+ opPos,
+ argLen,
+ stepType);
+
+ const eMatchScore score =
+ theTester(*context, context->getNodeType());
+ assert(score == nodeTest(executionContext, context,
context->getNodeType(), opPos, argLen, stepType));
+
+ if(eMatchScoreNone != score)
+ {
+ subQueryResults.addNode(context);
+ }
+ }
+
+ subQueryResults.setDocumentOrder();
+
+ return argLen + 3;
+}
+
+
+
+int
+XPath::findAncestors(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const
+{
+ assert(context != 0);
+
+ context = DOMServices::getParentOfNode(*context);
+
+ const XPathExpression& currentExpression = getExpression();
+
+ // $$ ToDO: Can we reduce this to some call on the
+ // XPathExpression interface?
+ const int argLen =
+ currentExpression.getOpCodeMapValue(opPos +
XPathExpression::s_opCodeMapLengthIndex + 1) - 3;
+
+ if (context != 0)
+ {
+ opPos += 3;
+
+ const NodeTester theTester(
+ *this,
+ executionContext,
+ opPos,
+ argLen,
+ stepType);
+
+ do
+ {
+ const eMatchScore score =
+ theTester(*context, context->getNodeType());
+ assert(score == nodeTest(executionContext,
context, context->getNodeType(), opPos, argLen, stepType));
+
+ if(eMatchScoreNone != score)
+ {
+ subQueryResults.addNode(context);
+ }
+
+ context = DOMServices::getParentOfNode(*context);
+ } while(0 != context);
+
+ subQueryResults.setReverseDocumentOrder();
+ }
+
+ return argLen + 3;
+}
+
+
+
+int
+XPath::findAncestorsOrSelf(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const
+{
+ assert(context != 0);
+
+ const XPathExpression& currentExpression = getExpression();
+
+ // $$ ToDO: Can we reduce this to some call on the
+ // XPathExpression interface?
+ const int argLen =
+ currentExpression.getOpCodeMapValue(opPos +
XPathExpression::s_opCodeMapLengthIndex + 1) - 3;
+
+ opPos += 3;
+
+ const NodeTester theTester(
+ *this,
+ executionContext,
+ opPos,
+ argLen,
+ stepType);
+
+ do
+ {
+ const eMatchScore score =
+ theTester(*context, context->getNodeType());
+ assert(score == nodeTest(executionContext,
context, context->getNodeType(), opPos, argLen, stepType));
+
+ if(eMatchScoreNone != score)
+ {
+ subQueryResults.addNode(context);
+ }
+
+ context = DOMServices::getParentOfNode(*context);
+ } while(0 != context);
+
+ subQueryResults.setReverseDocumentOrder();
+
+ return argLen + 3;
+}
+
+
+
+int
+XPath::findAttributes(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const
+{
+ assert(context != 0);
+
+ const XPathExpression& currentExpression = getExpression();
+
+ // $$ ToDO: Can we reduce this to some call on the
+ // XPathExpression interface?
+ const int argLen =
+ currentExpression.getOpCodeMapValue(opPos +
XPathExpression::s_opCodeMapLengthIndex + 1) - 3;
+
+ if(context->getNodeType() == XalanNode::ELEMENT_NODE)
+ {
+ const XalanNamedNodeMap* const attributeList =
context->getAttributes();
+
+ if(attributeList != 0)
+ {
+ opPos += 3;
+
+ const unsigned int nAttrs =
attributeList->getLength();
+
+ if (nAttrs != 0)
+ {
+ const NodeTester theTester(
+ *this,
+
executionContext,
+ opPos,
+ argLen,
+ stepType);
+
+ for(unsigned int j = 0; j < nAttrs; j++)
+ {
+ XalanNode* const theNode =
attributeList->item(j);
+ assert(theNode != 0 &&
theNode->getNodeType() == XalanNode::ATTRIBUTE_NODE);
+
+ const eMatchScore score =
+ theTester(*theNode,
XalanNode::ATTRIBUTE_NODE);
+ assert(score ==
nodeTest(executionContext, theNode, XalanNode::ATTRIBUTE_NODE, opPos, argLen,
stepType));
+
+ if(eMatchScoreNone != score)
+ {
+
subQueryResults.addNode(theNode);
+ }
+ }
+ }
+ }
+ }
+
+ return argLen + 3;
+}
+
+
+
+int
+XPath::findChildren(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const
+{
+ assert(context != 0);
+
+ XalanNode* child = context->getFirstChild();
+
+ const XPathExpression& currentExpression = getExpression();
+
+ // $$ ToDO: Can we reduce this to some call on the
+ // XPathExpression interface?
+ const int argLen =
+ currentExpression.getOpCodeMapValue(opPos +
XPathExpression::s_opCodeMapLengthIndex + 1) - 3;
+
+ if (child != 0)
+ {
+ opPos += 3;
+
+ const NodeTester theTester(
+ *this,
+ executionContext,
+ opPos,
+ argLen,
+ stepType);
+
+ do
+ {
+ const eMatchScore score =
+ theTester(*child, child->getNodeType());
+ assert(score ==
nodeTest(executionContext, child, child->getNodeType(), opPos, argLen,
stepType));
+
+ if(eMatchScoreNone != score)
+ {
+ subQueryResults.addNode(child);
+ }
+
+ child = child->getNextSibling();
+ } while(0 != child);
+
+ subQueryResults.setDocumentOrder();
+ }
+
+ return argLen + 3;
+}
+
+
+
+int
+XPath::findDescendants(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const
+{
+ assert(context != 0);
+
+ const XPathExpression& currentExpression = getExpression();
+
+ // $$ ToDO: Can we reduce this to some call on the
+ // XPathExpression interface?
+ const int argLen =
+ currentExpression.getOpCodeMapValue(opPos +
XPathExpression::s_opCodeMapLengthIndex + 1) - 3;
+
+ // Perform a pre-order traversal of descendents...
+ XalanNode* pos = context;
+
+ opPos += 3;
+
+ const NodeTester theTester(
+ *this,
+ executionContext,
+ opPos,
+ argLen,
+ stepType);
+
+ do
+ {
+ if(stepType == XPathExpression::eFROM_DESCENDANTS_OR_SELF ||
+ context != pos)
+ {
+ const eMatchScore score =
+ theTester(*pos, pos->getNodeType());
+ assert(score == nodeTest(executionContext, pos,
pos->getNodeType(), opPos, argLen, stepType));
+
+ if(score != eMatchScoreNone)
+ {
+ subQueryResults.addNode(pos);
+ }
+ }
+
+ XalanNode* nextNode = pos->getFirstChild();
+
+ while(0 == nextNode)
+ {
+ if(context == pos)
+ break;
+
+ nextNode = pos->getNextSibling();
+
+ if(0 == nextNode)
+ {
+ pos = DOMServices::getParentOfNode(*pos);
+
+ if(context == pos || pos == 0)
+ {
+ nextNode = 0;
+ break;
+ }
+ }
+ }
+
+ pos = nextNode;
+ } while(0 != pos);
+
+ subQueryResults.setDocumentOrder();
+
+ return argLen + 3;
+}
+
+
+
+int
+XPath::findFollowing(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const
+{
+ assert(context != 0);
+
+ const XPathExpression& currentExpression = getExpression();
+
+ // $$ ToDO: Can we reduce this to some call on the
+ // XPathExpression interface?
+ const int argLen =
+ currentExpression.getOpCodeMapValue(opPos +
XPathExpression::s_opCodeMapLengthIndex + 1) - 3;
+
+ opPos += 3;
+
+ // What fun...
+ XalanDocument* const doc = context->getOwnerDocument();
+
+ XalanNode* pos = context;
+
+ const NodeTester theTester(
+ *this,
+ executionContext,
+ opPos,
+ argLen,
+ stepType);
+
+ while(0 != pos)
+ {
+ XalanNode* nextNode = 0;
+
+ if(pos != context)
+ {
+ const eMatchScore score =
+ theTester(*pos, pos->getNodeType());
+ assert(score == nodeTest(executionContext, pos,
pos->getNodeType(), opPos, argLen, stepType));
+
+ if(eMatchScoreNone != score)
+ {
+ subQueryResults.addNodeInDocOrder(pos,
executionContext);
+ }
+
+ nextNode = pos->getFirstChild();
+ }
+ else
+ {
+ nextNode = 0;
+ }
+
+ while(0 == nextNode)
+ {
+ // This requires some explanation. pos could be an
attribute
+ // node, so getNextSibling() will always return 0. In
that
+ // case, I want to continue the search with the first
child of
+ // the owner element, as if attribute nodes are
children which
+ // are always _before_ the first child element. I
don't have to
+ // consider following attributes, since they _never_
match the
+ // following axis.
+ if (pos->getNodeType() == XalanNode::ATTRIBUTE_NODE)
+ {
+ assert(DOMServices::getParentOfNode(*pos) != 0);
+
+ nextNode =
DOMServices::getParentOfNode(*pos)->getFirstChild();
+ }
+ else
+ {
+ nextNode = pos->getNextSibling();
+ }
+
+ if(0 == nextNode)
+ {
+ pos = DOMServices::getParentOfNode(*pos);
+
+ if(doc == pos || 0 == pos)
+ {
+ nextNode = 0;
+
+ break;
+ }
+ }
+ }
+
+ pos = nextNode;
+ }
+
+ subQueryResults.setDocumentOrder();
+
+ return argLen + 3;
+}
+
+
+
+int
+XPath::findFollowingSiblings(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const
+{
+ assert(context != 0);
+
+ const XPathExpression& currentExpression = getExpression();
+
+ // $$ ToDO: Can we reduce this to some call on the
+ // XPathExpression interface?
+ const int argLen =
+ currentExpression.getOpCodeMapValue(opPos +
XPathExpression::s_opCodeMapLengthIndex + 1) - 3;
+
+ XalanNode* pos = context->getNextSibling();
+
+ if (pos != 0)
+ {
+ opPos += 3;
+
+ const NodeTester theTester(
+ *this,
+ executionContext,
+ opPos,
+ argLen,
+ stepType);
+
+ do
+ {
+ const eMatchScore score =
+ theTester(*pos, pos->getNodeType());
+ assert(score ==
nodeTest(executionContext, pos, pos->getNodeType(), opPos, argLen, stepType));
+
+ if(eMatchScoreNone != score)
+ {
+ subQueryResults.addNode(pos);
+ }
+
+ pos = pos->getNextSibling();
+ } while(0 != pos);
+
+ subQueryResults.setDocumentOrder();
+ }
+
+ return argLen + 3;
+}
+
+
+
+int
+XPath::findPreceeding(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const
+{
+ assert(context != 0);
+
+ const XPathExpression& currentExpression = getExpression();
+
+ // $$ ToDO: Can we reduce this to some call on the
+ // XPathExpression interface?
+ const int argLen =
+ currentExpression.getOpCodeMapValue(opPos +
XPathExpression::s_opCodeMapLengthIndex + 1) - 3;
+
+ opPos += 3;
+
+ // Ugh. Reverse document order, no parents, I guess.
+ XalanDocument* const doc = context->getOwnerDocument();
+
+ XalanNode* pos = doc;
+
+ // If the context node is an attribute, we need to perform some
+ // magic to stop the search at the appropriate point, which is when
+ // we arrive back at the parent.
+ const bool contextIsAttribute =
+ context->getNodeType() == XalanNode::ATTRIBUTE_NODE ?
true : false;
+
+ const XalanNode* const theAttributeContextParent =
+ contextIsAttribute == true ?
DOMServices::getParentOfNode(*context) : 0;
+
+ const NodeTester theTester(
+ *this,
+ executionContext,
+ opPos,
+ argLen,
+ stepType);
+
+ while(0 != pos)
+ {
+ if(context == pos)
+ {
+ break;
+ }
+
+ const eMatchScore score =
+ theTester(*pos, pos->getNodeType());
+ assert(score == nodeTest(executionContext, pos,
pos->getNodeType(), opPos, argLen, stepType));
+
+ if(eMatchScoreNone != score)
+ {
+ // Ugh. If I could think a little better tonight, I'm
+ // sure there's a better way to check for the parent.
+ bool isParent = false;
+
+ XalanNode* parent =
DOMServices::getParentOfNode(*context);
+
+ while(0 != parent)
+ {
+ if(parent == pos)
+ {
+ isParent = true;
+ break;
+ }
+
+ parent = DOMServices::getParentOfNode(*parent);
+ }
+
+ if(isParent == false)
+ {
+ subQueryResults.addNode(pos);
+ }
+ }
+
+ XalanNode* nextNode = 0;
+
+ // Check to see if we're back at the attribute context node's
+ // parent, in which case, we should stop.
+ if (contextIsAttribute == true &&
+ pos == theAttributeContextParent)
+ {
+ nextNode = context;
+ }
+ else
+ {
+ nextNode = pos->getFirstChild();
+ }
+
+ while(0 == nextNode)
+ {
+ nextNode = pos->getNextSibling();
+
+ if(0 == nextNode)
+ {
+ pos = DOMServices::getParentOfNode(*pos);
+
+ if(doc == pos)
+ {
+ nextNode = 0;
+ break;
+ }
+ }
+ }
+
+ pos = nextNode;
+ }
+
+ // Now, reverse the order of the nodes, since
+ // preceeding is a reverse axis, and we searched
+ // the document from the root to this node.
+ subQueryResults.reverse();
+
+ subQueryResults.setReverseDocumentOrder();
+
+ return argLen + 3;
+}
+
+
+
+int
+XPath::findPreceedingSiblings(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const
+{
+ assert(context != 0);
+
+ const XPathExpression& currentExpression = getExpression();
+
+ // $$ ToDO: Can we reduce this to some call on the
+ // XPathExpression interface?
+ const int argLen =
+ currentExpression.getOpCodeMapValue(opPos +
XPathExpression::s_opCodeMapLengthIndex + 1) - 3;
+
+ XalanNode* pos = context->getPreviousSibling();
+
+ if (pos != 0)
+ {
+ opPos += 3;
+
+ const NodeTester theTester(
+ *this,
+ executionContext,
+ opPos,
+ argLen,
+ stepType);
+
+ do
+ {
+ const eMatchScore score =
+ theTester(*pos, pos->getNodeType());
+ assert(score == nodeTest(executionContext, pos,
pos->getNodeType(), opPos, argLen, stepType));
+
+ if(eMatchScoreNone != score)
+ {
+ subQueryResults.addNode(pos);
+ }
+
+ pos = pos->getPreviousSibling();
+ } while(0 != pos);
+
+ subQueryResults.setReverseDocumentOrder();
+ }
+
+ return argLen + 3;
+}
+
+
+
+int
+XPath::findNamespace(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const
+{
+ assert(context != 0);
+
+ const XPathExpression& currentExpression = getExpression();
+
+ // $$ ToDO: Can we reduce this to some call on the
+ // XPathExpression interface?
+ const int argLen =
+ currentExpression.getOpCodeMapValue(opPos +
XPathExpression::s_opCodeMapLengthIndex + 1) - 3;
+
+ if(context->getNodeType() == XalanNode::ELEMENT_NODE)
+ {
+ opPos += 3;
+
+ // Look up the element chain until we hit the document, so that
we
+ // get all of the attribute/namespace nodes.
+ const XalanNode* const theOwnerDocument =
context->getOwnerDocument();
+ assert(theOwnerDocument != 0);
+
+ const XalanNode* theCurrentNode = context;
+
+ const NodeTester theTester(
+ *this,
+ executionContext,
+ opPos,
+ argLen,
+ stepType);
+
+ do
+ {
+ const XalanNamedNodeMap* const attributeList =
+ theCurrentNode->getAttributes();
+
+ if(attributeList != 0)
+ {
+ const unsigned int nAttrs =
attributeList->getLength();
+
+ for(unsigned int i = 0; i < nAttrs; ++i)
+ {
+ XalanNode* const attr =
attributeList->item(i);
+ assert(attr != 0 && attr->getNodeType()
== XalanNode::ATTRIBUTE_NODE);
+
+ const XalanDOMString& theNodeName =
attr->getNodeName();
+
+ // This is an optimization to keep
non-namespace attributes out of
+ // the call to nodeTest().
+ if (startsWith(theNodeName,
DOMServices::s_XMLNamespaceWithSeparator) == true ||
+ ::equals(theNodeName,
DOMServices::s_XMLNamespace) == true)
+ {
+ const eMatchScore score =
+ theTester(*attr,
XalanNode::ATTRIBUTE_NODE);
+ assert(score ==
nodeTest(executionContext, attr, XalanNode::ATTRIBUTE_NODE, opPos, argLen,
stepType));
+
+ if(score != eMatchScoreNone)
+ {
+
subQueryResults.addNode(attr);
+ }
+ }
+ }
+ }
+
+ theCurrentNode = theCurrentNode->getParentNode();
+ } while (theCurrentNode != theOwnerDocument && theCurrentNode
!= 0);
+ }
+
+ return argLen + 3;
+}
+
+
+
+int
+XPath::findNodesOnUnknownAxis(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int /* stepType */,
+ MutableNodeRefList& /* subQueryResults */) const
+{
+ const XPathExpression& currentExpression = getExpression();
+
+ // $$ ToDO: Can we reduce this to some call on the
+ // XPathExpression interface?
+ const int argLen =
+ currentExpression.getOpCodeMapValue(opPos +
XPathExpression::s_opCodeMapLengthIndex + 1) - 3;
+
+ executionContext.error(TranscodeFromLocalCodePage("Unknown axis!"),
context, getLocator());
+
+ return argLen + 3;
+}
+
+
+
+XPath::eMatchScore
+XPath::nodeTest(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ XalanNode::NodeType nodeType,
+ int opPos,
+ int argLen,
+ int stepType) const
+{
+ assert(context->getNodeType() == nodeType);
+
+ const XPathExpression& currentExpression = getExpression();
+
+ eMatchScore score = eMatchScoreNone;
+
+ const int testType = currentExpression.getOpCodeMapValue(opPos);
+
+ switch(testType)
+ {
+ case XPathExpression::eNODETYPE_COMMENT:
+ if (XalanNode::COMMENT_NODE == nodeType)
+ {
+ score = eMatchScoreNodeTest;
+ }
+ break;
+
+ case XPathExpression::eNODETYPE_TEXT:
+ if ((XalanNode::CDATA_SECTION_NODE == nodeType ||
+ XalanNode::TEXT_NODE == nodeType) &&
+ executionContext.shouldStripSourceNode(*context) ==
false)
+ {
+ score = eMatchScoreNodeTest;
+ }
+ break;
+
+ case XPathExpression::eNODETYPE_PI:
+ if(XalanNode::PROCESSING_INSTRUCTION_NODE == nodeType)
+ {
+ if(argLen == 1)
+ {
+ score = eMatchScoreNodeTest;
+ }
+ else if(argLen == 2)
+ {
+ opPos++;
+
+ const int
tokenPosition =
+
currentExpression.getOpCodeMapValue(opPos);
+
+ const XObject* const name =
+
currentExpression.getToken(tokenPosition);
+ assert(name != 0);
+
+ if (::equals(context->getNodeName(),
name->str()) == true)
+ {
+ score = eMatchScoreQName;
+ }
+ }
+ else
+ {
+
executionContext.error(TranscodeFromLocalCodePage("Arg length of
processing-instruction() node test is incorrect!"), context, getLocator());
+ }
+ }
+
+ break;
+
+ case XPathExpression::eNODETYPE_NODE:
+ if (nodeType == XalanNode::CDATA_SECTION_NODE ||
+ nodeType == XalanNode::TEXT_NODE)
+ {
+ if (executionContext.shouldStripSourceNode(*context) ==
false)
+ {
+ score = eMatchScoreNodeTest;
+ }
+ }
+ else
+ {
+ score = eMatchScoreNodeTest;
+ }
+ break;
+
+ case XPathExpression::eNODETYPE_ROOT:
+ if (XalanNode::DOCUMENT_FRAGMENT_NODE == nodeType ||
+ XalanNode::DOCUMENT_NODE == nodeType)
+ {
+ score = eMatchScoreOther;
+ }
+ break;
+
+ case XPathExpression::eNODENAME:
+ {
+ opPos++;
+
+ if (nodeType == XalanNode::ATTRIBUTE_NODE || nodeType
== XalanNode::ELEMENT_NODE)
+ {
+ bool test =
false;
+
+ int
queueIndex = currentExpression.getOpCodeMapValue(opPos);
+
+ const XalanDOMString& targetNS = queueIndex
>= 0 ?
+
currentExpression.getToken(queueIndex)->str() :
+
s_emptyString;
+
+ opPos++;
+
+ // From the draft: "Two expanded names are
equal if they
+ // have the same local part, and either both
have no URI or
+ // both have the same URI."
+ // "A node test * is true for any node of the
principal node type.
+ // For example, child::* will select all
element children of the
+ // context node, and attribute::* will select
all attributes of
+ // the context node."
+ // "A node test can have the form NCName:*. In
this case, the prefix
+ // is expanded in the same way as with a QName
using the context
+ // namespace declarations. The node test will
be true for any node
+ // of the principal type whose expanded name
has the URI to which
+ // the prefix expands, regardless of the local
part of the name."
+ const bool isTotallyWild =
+ 0 == length(targetNS) &&
+
currentExpression.getOpCodeMapValue(opPos) == XPathExpression::eELEMWILDCARD;
+
+ bool didMatchNS = false;
+
+ if(isTotallyWild == false)
+ {
+ const XalanDOMString& contextNS =
DOMServices::getNamespaceOfNode(*context);
+
+ if(0 != length(targetNS) && 0 !=
length(contextNS))
+ {
+ test = ::equals(contextNS,
targetNS);
+
+ didMatchNS = true;
+ }
+ else
+ {
+ test =
XPathExpression::eELEMWILDCARD == queueIndex ||
+ (0 == length(contextNS) && 0
== length(targetNS));
+ }
+ }
+ else
+ {
+ test = true;
+ }
+
+ queueIndex =
currentExpression.getOpCodeMapValue(opPos);
+
+ if(test == true)
+ {
+ switch(nodeType)
+ {
+ case XalanNode::ATTRIBUTE_NODE:
+ if(stepType ==
XPathExpression::eFROM_ATTRIBUTES ||
+ stepType ==
XPathExpression::eFROM_NAMESPACE)
+ {
+
assert(context->getNodeType() == XalanNode::ATTRIBUTE_NODE);
+
+ const XalanDOMString&
attrName =
+
context->getNodeName();
+
+ const bool
isNamespace =
+
startsWith(attrName, DOMServices::s_XMLNamespaceWithSeparator) ||
+
::equals(attrName, DOMServices::s_XMLNamespace);
+
+
if(XPathExpression::eELEMWILDCARD == queueIndex)
+ {
+ if(stepType ==
XPathExpression::eFROM_ATTRIBUTES)
+ {
+ if
(isNamespace == false)
+ {
+
score = eMatchScoreNodeTest;
+ }
+ }
+ else
+ {
+ if
(isNamespace == true)
+ {
+
score = eMatchScoreNodeTest;
+ }
+ }
+ }
+ else
+ {
+ if(stepType ==
XPathExpression::eFROM_ATTRIBUTES)
+ {
+ if
(isNamespace == false)
+ {
+
assert(queueIndex >= 0);
+
+
const XalanDOMString& targetLocalName =
+
currentExpression.getToken(queueIndex)->str();
+
+
const XalanDOMString& localAttrName =
+
DOMServices::getLocalNameOfNode(*context);
+
+
if (::equals(localAttrName, targetLocalName) == true)
+
{
+
score = eMatchScoreQName;
+
}
+ }
+ }
+ else
+ {
+ if
(isNamespace == true)
+ {
+
const XalanAttr* const theAttrNode =
+#if defined(XALAN_OLD_STYLE_CASTS)
+
(const XalanAttr*)context;
+#else
+
static_cast<const XalanAttr*>(context);
+#endif
+
assert(theAttrNode != 0);
+
+
const XalanDOMString& theNamespace =
+
theAttrNode->getValue();
+
+
assert(queueIndex >= 0);
+
+
const XalanDOMString& targetLocalName =
+
currentExpression.getToken(queueIndex)->str();
+
+
if (::equals(theNamespace, targetLocalName) == true)
+
{
+
score = eMatchScoreQName;
+
}
+ }
+ }
+ }
+ }
+ break;
+
+ case XalanNode::ELEMENT_NODE:
+ if(stepType !=
XPathExpression::eFROM_ATTRIBUTES)
+ {
+
if(XPathExpression::eELEMWILDCARD == queueIndex)
+ {
+ score =
didMatchNS == true ?
+
eMatchScoreNSWild : eMatchScoreNodeTest;
+ }
+ else
+ {
+
assert(queueIndex >= 0);
+
+ const
XalanDOMString& targetLocalName =
+
currentExpression.getToken(queueIndex)->str();
+
+ if
(::equals(DOMServices::getLocalNameOfNode(*context),
+
targetLocalName) == true)
+ {
+ score =
eMatchScoreQName;
+ }
+ }
+ }
+ break;
+
+ default:
+ // Trying to match on anything
else causes nasty bugs.
+ break;
+ } // end switch(nodeType)
+ } // end if(test)
+ } // end if (nodeType == XalanNode::ATTRIBUTE_NODE ||
nodeType == XalanNode::ELEMENT_NODE)
+ } // end case XPathExpression::eNODENAME
+ break;
+
+ default:
+ break;
+ } // end switch(testType)
+
+ return score;
+}
+
+
+
+void
+XPath::predicates(
+ XPathExecutionContext& executionContext,
+ XalanNode* /* context */,
+ int opPos,
+ MutableNodeRefList& subQueryResults,
+ int&
endPredicatesPos) const
+{
+ const XPathExpression& currentExpression = getExpression();
+
+ int nextStepType =
+ currentExpression.getOpCodeMapValue(opPos);
+
+ while(XPathExpression::eOP_PREDICATE == nextStepType)
+ {
+ NodeRefListBase::size_type i = 0;
+
+ const NodeRefListBase::size_type theLength =
subQueryResults.getLength();
+
+ while(i < theLength)
+ {
+ XalanNode* const theNode =
subQueryResults.item(i);
+ assert(theNode != 0);
+
+ const XObjectPtr pred(predicate(theNode,
opPos, executionContext));
+ assert(pred.get() != 0);
+
+ // Remove any node that doesn't satisfy the predicate.
+ if(XObject::eTypeNumber == pred->getType() &&
+ i + 1 != pred->num() ||
+ pred->boolean() == false)
+ {
+ // Set the node to 0. After we're done,
+ // we'll clear it out.
+ subQueryResults.setNode(i, 0);
+ }
+
+ ++i;
+ }
+
+ // Clear out any null entries...
+ subQueryResults.clearNulls();
+
+ opPos = currentExpression.getNextOpCodePosition(opPos);
+
+ nextStepType = currentExpression.getOpCodeMapValue(opPos);
+
+ if(XPathExpression::eOP_PREDICATE == nextStepType)
+ {
+ executionContext.setContextNodeList(subQueryResults);
+
+ // Don't break, loop 'till end so that opPos will be
set to end.
+ // if(0 == subQueryResults.getLength())
+ // break;
+ }
+ }
+
+ endPredicatesPos = opPos;
+}
+
+
+
+inline const XalanDOMString*
+getStringFromTokenQueue(
+ const XPathExpression& expression,
+ int opPos)
+{
+ const int tokenPosition =
+ expression.getOpCodeMapValue(opPos);
+
+ if (tokenPosition < 0)
+ {
+ return 0;
+ }
+ else
+ {
+ const XObject* const token =
+ expression.getToken(tokenPosition);
+ assert(token != 0);
+
+ return &token->str();
+ }
+}
+
+
+
+XPath::NodeTester::NodeTester(
+ const XPath& xpath,
+ XPathExecutionContext& executionContext,
+ int opPos,
+ int argLen,
+ int stepType) :
+ m_executionContext(executionContext),
+ m_targetNamespace(0),
+ m_targetLocalName(0),
+ m_testFunction(0)
+{
+ const XPathExpression& theExpression = xpath.getExpression();
+
+ switch(theExpression.getOpCodeMapValue(opPos))
+ {
+ case XPathExpression::eNODETYPE_COMMENT:
+ m_testFunction = &NodeTester::testComment;
+ break;
+
+ case XPathExpression::eNODETYPE_TEXT:
+ m_testFunction = &NodeTester::testText;
+ break;
+
+ case XPathExpression::eNODETYPE_PI:
+ if (argLen == 1)
+ {
+ m_testFunction = &NodeTester::testPI;
+ }
+ else if(argLen == 2)
+ {
+ m_testFunction = &NodeTester::testPIName;
+
+ m_targetLocalName = getStringFromTokenQueue(
+ theExpression,
+ opPos + 1);
+ }
+ else
+ {
+ executionContext.error(TranscodeFromLocalCodePage("Arg
length of processing-instruction() node test is incorrect!"), 0,
xpath.getLocator());
+ }
+ break;
+
+ case XPathExpression::eNODETYPE_NODE:
+ m_testFunction = &NodeTester::testNode;
+ break;
+
+ case XPathExpression::eNODETYPE_ROOT:
+ m_testFunction = &NodeTester::testRoot;
+ break;
+
+ case XPathExpression::eNODENAME:
+ {
+ bool isTotallyWild = false;
+
+ m_targetNamespace = getStringFromTokenQueue(
+ theExpression,
+ opPos + 1);
+
+ if (m_targetNamespace == 0 &&
+ theExpression.getOpCodeMapValue(opPos + 2) ==
XPathExpression::eELEMWILDCARD)
+ {
+ isTotallyWild = true;
+ }
+ else
+ {
+ m_targetLocalName = getStringFromTokenQueue(
+ theExpression,
+ opPos + 2);
+ }
+
+ if(stepType == XPathExpression::eFROM_ATTRIBUTES)
+ {
+ if (isTotallyWild == true)
+ {
+ m_testFunction =
&NodeTester::testAttributeTotallyWild;
+ }
+ else if (m_targetNamespace == 0)
+ {
+ assert(m_targetLocalName != 0);
+
+ m_testFunction =
&NodeTester::testAttributeNCName;
+ }
+ else if (m_targetLocalName == 0)
+ {
+ assert(m_targetNamespace != 0);
+
+ m_testFunction =
&NodeTester::testAttributeNamespaceOnly;
+ }
+ else
+ {
+ assert(m_targetNamespace != 0 &&
m_targetLocalName != 0);
+
+
+ m_testFunction =
&NodeTester::testAttributeQName;
+ }
+ }
+ else if (stepType == XPathExpression::eFROM_NAMESPACE)
+ {
+ if (isTotallyWild == true)
+ {
+ m_testFunction =
&NodeTester::testNamespaceTotallyWild;
+ }
+ else
+ {
+ m_testFunction =
&NodeTester::testNamespaceNCName;
+ }
+ }
+ else
+ {
+ if (isTotallyWild == true)
+ {
+ m_testFunction =
&NodeTester::testElementTotallyWild;
+ }
+ else if (m_targetNamespace == 0)
+ {
+ m_testFunction =
&NodeTester::testElementNCName;
+ }
+ else if (m_targetLocalName == 0)
+ {
+ assert(m_targetNamespace != 0);
+
+ m_testFunction =
&NodeTester::testElementNamespaceOnly;
+ }
+ else
+ {
+ assert(m_targetNamespace != 0 &&
m_targetLocalName != 0);
+
+ m_testFunction =
&NodeTester::testElementQName;
+ }
+ }
+ }
+ break;
+
+ default:
+ m_testFunction = &NodeTester::testDefault;
+ break;
+ }
+
+ assert(m_testFunction != 0);
+}
+
+
+
+XPath::eMatchScore
+XPath::NodeTester::testComment(
+ const XalanNode& /* context */,
+ XalanNode::NodeType nodeType) const
+{
+ if (XalanNode::COMMENT_NODE == nodeType)
+ {
+ return eMatchScoreNodeTest;
+ }
+ else
+ {
+ return eMatchScoreNone;
+ }
+}
+
+
+
+XPath::eMatchScore
+XPath::NodeTester::testText(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const
+{
+ if ((XalanNode::CDATA_SECTION_NODE == nodeType || XalanNode::TEXT_NODE
== nodeType) &&
+ shouldStripSourceNode(context) == false)
+ {
+ return eMatchScoreNodeTest;
+ }
+ else
+ {
+ return eMatchScoreNone;
+ }
+}
+
+
+
+XPath::eMatchScore
+XPath::NodeTester::testPI(
+ const XalanNode& /* context */,
+ XalanNode::NodeType nodeType) const
+{
+ if (XalanNode::PROCESSING_INSTRUCTION_NODE == nodeType)
+ {
+ return eMatchScoreNodeTest;
+ }
+ else
+ {
+ return eMatchScoreNone;
+ }
+}
+
+
+
+XPath::eMatchScore
+XPath::NodeTester::testPIName(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const
+{
+ assert(m_targetLocalName != 0);
+
+ if (XalanNode::PROCESSING_INSTRUCTION_NODE == nodeType &&
+ ::equals(context.getNodeName(), *m_targetLocalName) == true)
+ {
+ return eMatchScoreQName;
+ }
+ else
+ {
+ return eMatchScoreNone;
+ }
+}
+
+
+
+XPath::eMatchScore
+XPath::NodeTester::testNode(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const
+{
+ if ((nodeType != XalanNode::CDATA_SECTION_NODE && nodeType !=
XalanNode::TEXT_NODE) ||
+ shouldStripSourceNode(context) == false)
+ {
+ return eMatchScoreNodeTest;
+ }
+ else
+ {
+ return eMatchScoreNone;
+ }
+}
+
+
+
+XPath::eMatchScore
+XPath::NodeTester::testRoot(
+ const XalanNode& /* context */,
+ XalanNode::NodeType nodeType) const
+{
+ if (XalanNode::DOCUMENT_FRAGMENT_NODE == nodeType ||
+ XalanNode::DOCUMENT_NODE == nodeType)
+ {
+ return eMatchScoreOther;
+ }
+ else
+ {
+ return eMatchScoreNone;
+ }
+}
+
+
+
+inline bool
+isNamespaceDeclaration(const XalanNode& theAttributeNode)
+{
+ assert(theAttributeNode.getNodeType() == XalanNode::ATTRIBUTE_NODE);
+
+#if defined(XALAN_OLD_STYLE_CASTS)
+ return DOMServices::isNamespaceDeclaration((const
XalanAttr&)theAttributeNode);
+#else
+ return DOMServices::isNamespaceDeclaration(static_cast<const
XalanAttr&>(theAttributeNode));
+#endif
+}
+
+
+
+XPath::eMatchScore
+XPath::NodeTester::testAttributeNCName(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const
+{
+ assert(m_targetNamespace == 0 && m_targetLocalName != 0);
+
+ if (XalanNode::ATTRIBUTE_NODE != nodeType ||
+ isNamespaceDeclaration(context) == true ||
+ matchLocalName(context) == false)
+ {
+ return eMatchScoreNone;
+ }
+ else
+ {
+ return eMatchScoreQName;
+ }
+}
+
+
+
+XPath::eMatchScore
+XPath::NodeTester::testAttributeQName(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const
+{
+ assert(m_targetNamespace != 0 && m_targetLocalName != 0);
+
+ if (XalanNode::ATTRIBUTE_NODE != nodeType ||
+ isNamespaceDeclaration(context) == true ||
+ matchLocalNameAndNamespaceURI(context) == false)
+ {
+ return eMatchScoreNone;
+ }
+ else
+ {
+ return eMatchScoreQName;
+ }
+}
+
+
+
+XPath::eMatchScore
+XPath::NodeTester::testAttributeNamespaceOnly(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const
+{
+ assert(m_targetNamespace != 0 && m_targetLocalName == 0);
+
+ if (XalanNode::ATTRIBUTE_NODE != nodeType ||
+ isNamespaceDeclaration(context) == true ||
+ matchNamespaceURI(context) == false)
+ {
+ return eMatchScoreNone;
+ }
+ else
+ {
+ return eMatchScoreNodeTest;
+ }
+}
+
+
+
+XPath::eMatchScore
+XPath::NodeTester::testAttributeTotallyWild(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const
+{
+ if (XalanNode::ATTRIBUTE_NODE != nodeType ||
+ isNamespaceDeclaration(context) == true)
+ {
+ return eMatchScoreNone;
+ }
+ else
+ {
+ return eMatchScoreNodeTest;
+ }
+}
+
+
+
+XPath::eMatchScore
+XPath::NodeTester::testElementNCName(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const
+{
+ assert(m_targetNamespace == 0 && m_targetLocalName != 0);
+
+ if (XalanNode::ELEMENT_NODE != nodeType ||
+ matchLocalName(context) == false)
+ {
+ return eMatchScoreNone;
+ }
+ else
+ {
+ return eMatchScoreQName;
+ }
+}
+
+
+
+XPath::eMatchScore
+XPath::NodeTester::testElementQName(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const
+{
+ assert(m_targetNamespace != 0 && m_targetLocalName != 0);
+
+ if (XalanNode::ELEMENT_NODE != nodeType ||
+ matchLocalNameAndNamespaceURI(context) == false)
+ {
+ return eMatchScoreNone;
+ }
+ else
+ {
+ return eMatchScoreQName;
+ }
+}
+
+
+
+XPath::eMatchScore
+XPath::NodeTester::testElementNamespaceOnly(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const
+{
+ assert(m_targetNamespace != 0 && m_targetLocalName == 0);
+
+ if (XalanNode::ELEMENT_NODE != nodeType ||
+ matchNamespaceURI(context) == false)
+ {
+ return eMatchScoreNone;
+ }
+ else
+ {
+ return eMatchScoreNSWild;
+ }
+}
+
+
+
+XPath::eMatchScore
+XPath::NodeTester::testElementTotallyWild(
+ const XalanNode& /* context */,
+ XalanNode::NodeType nodeType) const
+{
+ assert(m_targetNamespace == 0 && m_targetLocalName == 0);
+
+ if (XalanNode::ELEMENT_NODE != nodeType)
+ {
+ return eMatchScoreNone;
+ }
+ else
+ {
+ return eMatchScoreNodeTest;
+ }
+}
+
+
+
+XPath::eMatchScore
+XPath::NodeTester::testNamespaceNCName(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const
+{
+ assert(m_targetNamespace == 0 && m_targetLocalName != 0);
+
+ if (XalanNode::ATTRIBUTE_NODE != nodeType ||
+ isNamespaceDeclaration(context) == false ||
+ matchNamespace(context) == false)
+ {
+ return eMatchScoreNone;
+ }
+ else
+ {
+ return eMatchScoreQName;
+ }
+}
+
+
+
+XPath::eMatchScore
+XPath::NodeTester::testNamespaceTotallyWild(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const
+{
+ assert(m_targetNamespace == 0 && m_targetLocalName == 0);
+
+ if (XalanNode::ATTRIBUTE_NODE != nodeType ||
+ isNamespaceDeclaration(context) == false)
+ {
+ return eMatchScoreNone;
+ }
+ else
+ {
+ return eMatchScoreNodeTest;
+ }
+}
+
+
+
+XPath::eMatchScore
+XPath::NodeTester::testDefault(
+ const XalanNode& /* context */,
+ XalanNode::NodeType /* nodeType */) const
+{
+ return eMatchScoreNone;
+}
+
+
+
+bool
+XPath::NodeTester::matchLocalName(const XalanNode& context) const
+{
+ assert(m_targetLocalName != 0);
+
+ return length(context.getNamespaceURI()) == 0 &&
+ ::equals(DOMServices::getLocalNameOfNode(context),
*m_targetLocalName);
+}
+
+
+
+bool
+XPath::NodeTester::matchNamespaceURI(const XalanNode& context) const
+{
+ assert(m_targetNamespace != 0);
+
+ return ::equals(context.getNamespaceURI(), *m_targetNamespace);
+}
+
+
+
+bool
+XPath::NodeTester::matchLocalNameAndNamespaceURI(const XalanNode&
context) const
+{
+ assert(m_targetNamespace != 0 && m_targetLocalName != 0);
+
+ return ::equals(DOMServices::getLocalNameOfNode(context),
*m_targetLocalName) == true &&
+ ::equals(context.getNamespaceURI(), *m_targetNamespace) == true;
+}
+
+
+
+bool
+XPath::NodeTester::matchNamespace(const XalanNode& context) const
+{
+ assert(m_targetLocalName != 0);
+
+ return ::equals(context.getNodeValue(), *m_targetLocalName);
+}
+
+
+
+bool
+XPath::NodeTester::shouldStripSourceNode(const XalanNode& context) const
+{
+ assert(context.getNodeType() == XalanNode::CDATA_SECTION_NODE ||
+ context.getNodeType() == XalanNode::TEXT_NODE);
+
+ return m_executionContext.shouldStripSourceNode(context);
}
1.30 +319 -0 xml-xalan/c/src/XPath/XPath.hpp
Index: XPath.hpp
===================================================================
RCS file: /home/cvs/xml-xalan/c/src/XPath/XPath.hpp,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -r1.29 -r1.30
--- XPath.hpp 2001/09/14 20:06:26 1.29
+++ XPath.hpp 2001/10/24 15:44:51 1.30
@@ -813,6 +813,323 @@
eDefaultTargetStringsSize = 5
};
+ const XObjectPtr
+ locationPath(
+ XPathExecutionContext& executionContext,
+ XalanNode& context,
+ int opPos) const;
+
+ eMatchScore
+ locationPathPattern(
+ XPathExecutionContext& executionContext,
+ XalanNode& context,
+ int opPos) const;
+
+ class NodeTester
+ {
+ public:
+
+ NodeTester(
+ const XPath& xpath,
+ XPathExecutionContext& executionContext,
+ int opPos,
+ int argLen,
+ int stepType);
+
+ eMatchScore
+ operator()(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const
+ {
+ assert(context.getNodeType() == nodeType);
+
+ return (this->*m_testFunction)(context, nodeType);
+ }
+
+ private:
+
+ typedef eMatchScore (NodeTester::*MemberFunctionPtr)(const
XalanNode&, XalanNode::NodeType) const;
+
+
+ eMatchScore
+ testComment(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const;
+
+ eMatchScore
+ testText(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const;
+
+ eMatchScore
+ testPI(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const;
+
+ eMatchScore
+ testPIName(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const;
+
+ eMatchScore
+ testNode(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const;
+
+ eMatchScore
+ testRoot(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const;
+
+ eMatchScore
+ testAttributeNCName(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const;
+
+ eMatchScore
+ testAttributeQName(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const;
+
+ eMatchScore
+ testAttributeNamespaceOnly(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const;
+
+ eMatchScore
+ testAttributeTotallyWild(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const;
+
+ eMatchScore
+ testElementNCName(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const;
+
+ eMatchScore
+ testElementQName(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const;
+
+ eMatchScore
+ testElementNamespaceOnly(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const;
+
+ eMatchScore
+ testElementTotallyWild(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const;
+
+ eMatchScore
+ testNamespaceNCName(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const;
+
+ eMatchScore
+ testNamespaceTotallyWild(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const;
+
+ eMatchScore
+ testDefault(
+ const XalanNode& context,
+ XalanNode::NodeType nodeType) const;
+
+ bool
+ matchLocalName(const XalanNode& context) const;
+
+ bool
+ matchNamespaceURI(const XalanNode& context) const;
+
+ bool
+ matchLocalNameAndNamespaceURI(const XalanNode& context) const;
+
+ bool
+ matchNamespace(const XalanNode& context) const;
+
+ bool
+ shouldStripSourceNode(const XalanNode& context) const;
+
+ // Data members...
+ XPathExecutionContext& m_executionContext;
+
+ const XalanDOMString* m_targetNamespace;
+
+ const XalanDOMString* m_targetLocalName;
+
+ MemberFunctionPtr m_testFunction;
+ };
+
+protected:
+
+ void
+ step(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ MutableNodeRefList& queryResults) const;
+
+ /**
+ * Execute a step in a location path.
+ *
+ * @param xpath The xpath that is executing
+ * @param context The current source tree context node
+ * @param opPos The current position in the xpath operation map array
+ * @param scoreHolder a reference to an eMatchScore to receive
+ * the result.
+ * @return the last matched context node
+ */
+ XalanNode*
+ stepPattern(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ eMatchScore& scoreHolder) const;
+
+ int
+ findNodeSet(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const;
+
+ int
+ findRoot(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const;
+
+ int
+ findParent(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const;
+
+ int
+ findSelf(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const;
+
+ int
+ findAncestors(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const;
+
+ int
+ findAncestorsOrSelf(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const;
+
+ int
+ findAttributes(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const;
+
+ int
+ findChildren(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const;
+
+ int
+ findDescendants(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const;
+
+ int
+ findFollowing(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const;
+
+ int
+ findFollowingSiblings(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const;
+
+ int
+ findPreceeding(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const;
+
+ int
+ findPreceedingSiblings(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const;
+
+ int
+ findNamespace(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const;
+
+ int
+ findNodesOnUnknownAxis(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ int stepType,
+ MutableNodeRefList& subQueryResults) const;
+
+ eMatchScore
+ nodeTest(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ XalanNode::NodeType nodeType,
+ int opPos,
+ int argLen,
+ int stepType) const;
+
+ void
+ predicates(
+ XPathExecutionContext& executionContext,
+ XalanNode* context,
+ int opPos,
+ MutableNodeRefList& subQueryResults,
+ int&
endPredicatesPos) const;
+
+ eMatchScore
+ handleFoundIndex(
+ XPathExecutionContext& executionContext,
+ XalanNode* localContext,
+ int startOpPos)
const;
+
// Data members...
/**
@@ -840,6 +1157,8 @@
*
*/
static FunctionTableType s_functions;
+
+ static const XalanDOMString s_emptyString;
};
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]