sicking%bigfoot.com 6265d66757 Speed up NodeSets by always keeping them in document order. Only sort when we get nodes in random order (such as for id()) or when merging NodeSets.
This removes the need for the sortByDocumentOrder function.

b=85893 r=Pike rs=jag


git-svn-id: svn://10.0.0.236/trunk@113703 18797224-902f-48f8-a5cc-f745e15eee43
2002-02-05 14:22:34 +00:00

1077 lines
32 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is TransforMiiX XSLT processor.
*
* The Initial Developer of the Original Code is The MITRE Corporation.
* Portions created by MITRE are Copyright (C) 1999 The MITRE Corporation.
*
* Portions created by Keith Visco as a Non MITRE employee,
* (C) 1999-2000 Keith Visco. All Rights Reserved.
*
* Contributor(s):
* Keith Visco, kvisco@ziplink.net
* -- original author.
*
* Olivier Gerardin, ogerardin@vo.lu
* -- added code in ::resolveFunctionCall to support the
* document() function.
*
*/
/**
* Implementation of ProcessorState
* Much of this code was ported from XSL:P
**/
#include "ProcessorState.h"
#include "XSLTFunctions.h"
#include "FunctionLib.h"
#include "URIUtils.h"
#include "XMLUtils.h"
#include "XMLDOMUtils.h"
#include "Tokenizer.h"
#include "VariableBinding.h"
#include "ExprResult.h"
#include "Names.h"
#include "XMLParser.h"
#include "txAtoms.h"
/**
* Creates a new ProcessorState
**/
ProcessorState::ProcessorState() : mXPathParseContext(0),
mSourceDocument(0),
xslDocument(0),
resultDocument(0)
{
initialize();
} //-- ProcessorState
/**
* Creates a new ProcessorState for the given XSL document
* and resultDocument
**/
ProcessorState::ProcessorState(Document* aSourceDocument,
Document* aXslDocument,
Document* aResultDocument)
: mXPathParseContext(0),
mSourceDocument(aSourceDocument),
xslDocument(aXslDocument),
resultDocument(aResultDocument)
{
initialize();
} //-- ProcessorState
/**
* Destroys this ProcessorState
**/
ProcessorState::~ProcessorState()
{
while (! variableSets.empty()) {
delete (NamedMap*) variableSets.pop();
}
// Delete all ImportFrames
txListIterator iter(&mImportFrames);
while (iter.hasNext())
delete (ImportFrame*)iter.next();
// Make sure that xslDocument and mSourceDocument aren't deleted along with
// the rest of the documents in the loadedDocuments hash
if (xslDocument)
loadedDocuments.remove(xslDocument->getBaseURI());
if (mSourceDocument)
loadedDocuments.remove(mSourceDocument->getBaseURI());
} //-- ~ProcessorState
/*
* Adds the given attribute set to the list of available named attribute
* sets
* @param aAttributeSet the Element to add as a named attribute set
* @param aImportFrame ImportFrame to add the attributeset to
*/
void ProcessorState::addAttributeSet(Element* aAttributeSet,
ImportFrame* aImportFrame)
{
if (!aAttributeSet)
return;
const String& name = aAttributeSet->getAttribute(NAME_ATTR);
if (name.isEmpty()) {
String err("missing required name attribute for xsl:attribute-set");
recieveError(err);
return;
}
// Get attribute set, if already exists, then merge
NodeSet* attSet = (NodeSet*)aImportFrame->mNamedAttributeSets.get(name);
if (!attSet) {
attSet = new NodeSet();
aImportFrame->mNamedAttributeSets.put(name, attSet);
}
// Add xsl:attribute elements to attSet
Node* node = aAttributeSet->getFirstChild();
while (node) {
if (node->getNodeType() == Node::ELEMENT_NODE) {
PRInt32 nsID = node->getNamespaceID();
if (nsID != kNameSpaceID_XSLT)
continue;
txAtom* nodeName;
if (!node->getLocalName(&nodeName) || !nodeName)
continue;
if (nodeName == txXSLTAtoms::attribute)
attSet->append(node);
TX_RELEASE_ATOM(nodeName);
}
node = node->getNextSibling();
}
}
/**
* Registers the given ErrorObserver with this ProcessorState
**/
void ProcessorState::addErrorObserver(ErrorObserver& errorObserver) {
errorObservers.add(&errorObserver);
} //-- addErrorObserver
/**
* Adds the given template to the list of templates to process
* @param xslTemplate The Element to add as a template
* @param importFrame ImportFrame to add the template to
**/
void ProcessorState::addTemplate(Element* aXslTemplate,
ImportFrame* aImportFrame)
{
NS_ASSERTION(aXslTemplate, "missing template");
const String& name = aXslTemplate->getAttribute(NAME_ATTR);
if (!name.isEmpty()) {
// check for duplicates
Element* tmp = (Element*)aImportFrame->mNamedTemplates.get(name);
if (tmp) {
String err("Duplicate template name: ");
err.append(name);
recieveError(err);
return;
}
aImportFrame->mNamedTemplates.put(name, aXslTemplate);
}
const String& match = aXslTemplate->getAttribute(MATCH_ATTR);
if (!match.isEmpty()) {
// get the txList for the right mode
const String& mode = aXslTemplate->getAttribute(MODE_ATTR);
txList* templates =
(txList*)aImportFrame->mMatchableTemplates.get(mode);
if (!templates) {
templates = new txList;
if (!templates) {
NS_ASSERTION(0, "out of memory");
return;
}
aImportFrame->mMatchableTemplates.put(mode, templates);
}
// Add the template to the list of templates
MatchableTemplate* templ = new MatchableTemplate;
if (!templ) {
NS_ASSERTION(0, "out of memory");
return;
}
templ->mTemplate = aXslTemplate;
Element* oldContext = mXPathParseContext;
mXPathParseContext = aXslTemplate;
templ->mMatch = exprParser.createPattern(match);
mXPathParseContext = oldContext;
if (templ->mMatch)
templates->add(templ);
else
delete templ;
}
}
/*
* Adds the given LRE Stylesheet to the list of templates to process
* @param aStylesheet The Stylesheet to add as a template
* @param importFrame ImportFrame to add the template to
*/
void ProcessorState::addLREStylesheet(Document* aStylesheet,
ImportFrame* aImportFrame)
{
NS_ASSERTION(aStylesheet, "missing stylesheet");
// get the txList for null mode
txList* templates =
(txList*)aImportFrame->mMatchableTemplates.get(NULL_STRING);
if (!templates) {
templates = new txList;
if (!templates) {
// XXX ErrorReport: out of memory
return;
}
aImportFrame->mMatchableTemplates.put(NULL_STRING, templates);
}
// Add the template to the list of templates
MatchableTemplate* templ = new MatchableTemplate;
if (!templ) {
// XXX ErrorReport: out of memory
return;
}
templ->mTemplate = aStylesheet;
String match("/");
templ->mMatch = exprParser.createPattern(match);
if (templ->mMatch)
templates->add(templ);
else
delete templ;
}
/*
* Retrieve the document designated by the URI uri, using baseUri as base URI.
* Parses it as an XML document, and returns it. If a fragment identifier is
* supplied, the element with seleced id is returned.
* The returned document is owned by the ProcessorState
*
* @param uri the URI of the document to retrieve
* @param baseUri the base URI used to resolve the URI if uri is relative
* @return loaded document or element pointed to by fragment identifier. If
* loading or parsing fails NULL will be returned.
*/
Node* ProcessorState::retrieveDocument(const String& uri, const String& baseUri)
{
String absUrl, frag, docUrl;
URIUtils::resolveHref(uri, baseUri, absUrl);
URIUtils::getFragmentIdentifier(absUrl, frag);
URIUtils::getDocumentURI(absUrl, docUrl);
// try to get already loaded document
Document* xmlDoc = (Document*)loadedDocuments.get(docUrl);
if (!xmlDoc) {
// open URI
String errMsg;
XMLParser xmlParser;
xmlDoc = xmlParser.getDocumentFromURI(docUrl, xslDocument, errMsg);
if (!xmlDoc) {
String err("Couldn't load document '");
err.append(docUrl);
err.append("': ");
err.append(errMsg);
recieveError(err, ErrorObserver::WARNING);
return NULL;
}
// add to list of documents
loadedDocuments.put(docUrl, xmlDoc);
}
// return element with supplied id if supplied
if (!frag.isEmpty())
return xmlDoc->getElementById(frag);
return xmlDoc;
}
/*
* Return stack of urls of currently entered stylesheets
*/
Stack* ProcessorState::getEnteredStylesheets()
{
return &enteredStylesheets;
}
/*
* Return list of import containers
*/
List* ProcessorState::getImportFrames()
{
return &mImportFrames;
}
/*
* Find template in specified mode matching the supplied node
* @param aNode node to find matching template for
* @param aMode mode of the template
* @param aImportFrame out-param, is set to the ImportFrame containing
* the found template
* @return root-node of found template, null if none is found
*/
Node* ProcessorState::findTemplate(Node* aNode,
const String& aMode,
ImportFrame** aImportFrame)
{
return findTemplate(aNode, aMode, 0, aImportFrame);
}
/*
* Find template in specified mode matching the supplied node. Only search
* templates imported by a specific ImportFrame
* @param aNode node to find matching template for
* @param aMode mode of the template
* @param aImportedBy seach only templates imported by this ImportFrame,
* or null to search all templates
* @param aImportFrame out-param, is set to the ImportFrame containing
* the found template
* @return root-node of found template, null if none is found
*/
Node* ProcessorState::findTemplate(Node* aNode,
const String& aMode,
ImportFrame* aImportedBy,
ImportFrame** aImportFrame)
{
NS_ASSERTION(aImportFrame, "missing ImportFrame pointer");
NS_ASSERTION(aNode, "missing node");
if (!aNode)
return 0;
Node* matchTemplate = 0;
double currentPriority = Double::NEGATIVE_INFINITY;
ImportFrame* endFrame = 0;
txListIterator frameIter(&mImportFrames);
if (aImportedBy) {
ImportFrame* curr = (ImportFrame*)frameIter.next();
while (curr != aImportedBy)
curr = (ImportFrame*)frameIter.next();
endFrame = aImportedBy->mFirstNotImported;
}
ImportFrame* frame;
while (!matchTemplate &&
(frame = (ImportFrame*)frameIter.next()) &&
frame != endFrame) {
// get templatelist for this mode
txList* templates;
templates = (txList*)frame->mMatchableTemplates.get(aMode);
if (templates) {
txListIterator templateIter(templates);
// Find template with highest priority
MatchableTemplate* templ;
while ((templ = (MatchableTemplate*)templateIter.next())) {
String priorityAttr;
if (templ->mTemplate->getNodeType() == Node::ELEMENT_NODE) {
Element* elem = (Element*)templ->mTemplate;
elem->getAttr(txXSLTAtoms::priority, kNameSpaceID_None,
priorityAttr);
}
double tmpPriority;
if (!priorityAttr.isEmpty()) {
tmpPriority = Double::toDouble(priorityAttr);
}
else {
tmpPriority = templ->mMatch->getDefaultPriority(aNode,
0,
this);
}
if (tmpPriority >= currentPriority &&
templ->mMatch->matches(aNode, 0, this)) {
matchTemplate = templ->mTemplate;
*aImportFrame = frame;
currentPriority = tmpPriority;
}
}
}
}
return matchTemplate;
}
/*
* Gets current template rule
*/
ProcessorState::TemplateRule* ProcessorState::getCurrentTemplateRule()
{
return mCurrentTemplateRule;
}
/*
* Sets current template rule
*/
void ProcessorState::setCurrentTemplateRule(TemplateRule* aTemplateRule)
{
mCurrentTemplateRule = aTemplateRule;
}
/**
* Returns the AttributeSet associated with the given name
* or null if no AttributeSet is found
*/
NodeSet* ProcessorState::getAttributeSet(const String& aName)
{
NodeSet* attset = new NodeSet;
if (!attset)
return attset;
ImportFrame* frame;
txListIterator frameIter(&mImportFrames);
frameIter.resetToEnd();
while ((frame = (ImportFrame*)frameIter.previous())) {
NodeSet* nodes = (NodeSet*)frame->mNamedAttributeSets.get(aName);
if (nodes)
attset->append(nodes);
}
return attset;
}
/**
* Returns the source node currently being processed
**/
Node* ProcessorState::getCurrentNode() {
return currentNodeStack.peek();
} //-- setCurrentNode
Expr* ProcessorState::getExpr(Element* aElem, ExprAttr aAttr)
{
NS_ASSERTION(aElem, "missing element while getting expression");
// This is how we'll have to do it for now
mXPathParseContext = aElem;
Expr* expr = (Expr*)mExprHashes[aAttr].get(aElem);
if (!expr) {
String attr;
switch (aAttr) {
case SelectAttr:
aElem->getAttr(txXSLTAtoms::select, kNameSpaceID_None,
attr);
break;
case TestAttr:
aElem->getAttr(txXSLTAtoms::test, kNameSpaceID_None,
attr);
break;
case ValueAttr:
aElem->getAttr(txXSLTAtoms::value, kNameSpaceID_None,
attr);
break;
}
// This is how we should do it once we namespaceresolve during parsing
//Element* oldContext = mXPathParseContext;
//mXPathParseContext = aElem;
expr = exprParser.createExpr(attr);
//mXPathParseContext = oldContext;
if (!expr) {
String err = "Error in parsing XPath expression: ";
err.append(attr);
recieveError(err);
}
else {
mExprHashes[aAttr].put(aElem, expr);
}
}
return expr;
}
PatternExpr* ProcessorState::getPattern(Element* aElem, PatternAttr aAttr)
{
NS_ASSERTION(aElem, "missing element while getting pattern");
// This is how we'll have to do it for now
mXPathParseContext = aElem;
Pattern* pattern = (Pattern*)mExprHashes[aAttr].get(aElem);
if (!pattern) {
String attr;
switch (aAttr) {
case CountAttr:
aElem->getAttr(txXSLTAtoms::count, kNameSpaceID_None,
attr);
break;
case FromAttr:
aElem->getAttr(txXSLTAtoms::from, kNameSpaceID_None,
attr);
break;
}
// This is how we should do it once we namespaceresolve during parsing
//Element* oldContext = mXPathParseContext;
//mXPathParseContext = aElem;
pattern = exprParser.createPattern(attr);
//mXPathParseContext = oldContext;
if (!pattern) {
String err = "Error in parsing pattern: ";
err.append(attr);
recieveError(err);
}
else {
mPatternHashes[aAttr].put(aElem, pattern);
}
}
return pattern;
}
/*
* Returns the template associated with the given name, or
* null if not template is found
*/
Element* ProcessorState::getNamedTemplate(String& aName)
{
ImportFrame* frame;
txListIterator frameIter(&mImportFrames);
while ((frame = (ImportFrame*)frameIter.next())) {
Element* templ = (Element*)frame->mNamedTemplates.get(aName);
if (templ)
return templ;
}
return 0;
}
void ProcessorState::getNameSpaceURIFromPrefix(const String& aPrefix,
String& aNamespaceURI)
{
if (mXPathParseContext)
XMLDOMUtils::getNamespaceURI(aPrefix, mXPathParseContext,
aNamespaceURI);
}
txOutputFormat* ProcessorState::getOutputFormat()
{
return &mOutputFormat;
}
Document* ProcessorState::getResultDocument()
{
return resultDocument;
}
Stack* ProcessorState::getVariableSetStack()
{
return &variableSets;
}
/*
* Determines if the given XSL node allows Whitespace stripping
*/
MBool ProcessorState::isXSLStripSpaceAllowed(Node* node) {
if (!node)
return MB_FALSE;
return (MBool)(getXMLSpaceMode(node) != PRESERVE);
}
/**
* Removes and returns the current source node being processed, from the stack
* @return the current source node
**/
Node* ProcessorState::popCurrentNode() {
return currentNodeStack.pop();
} //-- popCurrentNode
void ProcessorState::processAttrValueTemplate(const String& aAttValue,
Node* aContext,
String& aResult)
{
aResult.clear();
AttributeValueTemplate* avt =
exprParser.createAttributeValueTemplate(aAttValue);
if (!avt) {
// XXX ErrorReport: out of memory
return;
}
ExprResult* exprResult = avt->evaluate(aContext, this);
delete avt;
if (!exprResult) {
// XXX ErrorReport: out of memory
return;
}
exprResult->stringValue(aResult);
delete exprResult;
}
/**
* Sets the source node currently being processed
* @param node the source node to set as the "current" node
**/
void ProcessorState::pushCurrentNode(Node* node) {
currentNodeStack.push(node);
} //-- setCurrentNode
/**
* Adds the set of names to the Whitespace handling list.
* xsl:strip-space calls this with MB_TRUE, xsl:preserve-space
* with MB_FALSE
*/
void ProcessorState::shouldStripSpace(String& aNames,
MBool aShouldStrip,
ImportFrame* aImportFrame)
{
//-- split names on whitespace
txTokenizer tokenizer(aNames);
String name;
while (tokenizer.hasMoreTokens()) {
tokenizer.nextToken(name);
txNameTestItem* nti = new txNameTestItem(name, aShouldStrip);
if (!nti) {
// XXX error report, parsing error or out of mem
break;
}
double priority = nti->getDefaultPriority();
txListIterator iter(&aImportFrame->mWhiteNameTests);
while (iter.hasNext()) {
txNameTestItem* iNameTest = (txNameTestItem*)iter.next();
if (iNameTest->getDefaultPriority() <= priority) {
break;
}
}
iter.addBefore(nti);
}
} //-- stripSpace
/**
* Adds the supplied xsl:key to the set of keys
**/
MBool ProcessorState::addKey(Element* aKeyElem)
{
String keyName;
aKeyElem->getAttr(txXSLTAtoms::name, kNameSpaceID_None, keyName);
if (!XMLUtils::isValidQName(keyName))
return MB_FALSE;
txXSLKey* xslKey = (txXSLKey*)xslKeys.get(keyName);
if (!xslKey) {
xslKey = new txXSLKey(this);
if (!xslKey)
return MB_FALSE;
xslKeys.put(keyName, xslKey);
}
Element* oldContext = mXPathParseContext;
mXPathParseContext = aKeyElem;
Pattern* match;
match = exprParser.createPattern(aKeyElem->getAttribute(MATCH_ATTR));
Expr* use = exprParser.createExpr(aKeyElem->getAttribute(USE_ATTR));
mXPathParseContext = oldContext;
if (!match || !use || !xslKey->addKey(match, use)) {
delete match;
delete use;
return MB_FALSE;
}
return MB_TRUE;
}
/**
* Adds the supplied xsl:key to the set of keys
* returns NULL if no such key exists
**/
txXSLKey* ProcessorState::getKey(String& keyName) {
return (txXSLKey*)xslKeys.get(keyName);
}
/*
* Adds a decimal format. Returns false if the format already exists
* but dosn't contain the exact same parametervalues
*/
MBool ProcessorState::addDecimalFormat(Element* element)
{
// build new DecimalFormat structure
MBool success = MB_TRUE;
txDecimalFormat* format = new txDecimalFormat;
if (!format)
return MB_FALSE;
String attValue = element->getAttribute(NAME_ATTR);
String formatName = attValue;
if (element->getAttr(txXSLTAtoms::decimalSeparator,
kNameSpaceID_None, attValue)) {
if (attValue.length() == 1)
format->mDecimalSeparator = attValue.charAt(0);
else
success = MB_FALSE;
}
if (element->getAttr(txXSLTAtoms::groupingSeparator,
kNameSpaceID_None, attValue)) {
if (attValue.length() == 1)
format->mGroupingSeparator = attValue.charAt(0);
else
success = MB_FALSE;
}
if (element->getAttr(txXSLTAtoms::infinity,
kNameSpaceID_None, attValue))
format->mInfinity=attValue;
if (element->getAttr(txXSLTAtoms::minusSign,
kNameSpaceID_None, attValue)) {
if (attValue.length() == 1)
format->mMinusSign = attValue.charAt(0);
else
success = MB_FALSE;
}
if (element->getAttr(txXSLTAtoms::NaN, kNameSpaceID_None,
attValue))
format->mNaN=attValue;
if (element->getAttr(txXSLTAtoms::percent, kNameSpaceID_None,
attValue)) {
if (attValue.length() == 1)
format->mPercent = attValue.charAt(0);
else
success = MB_FALSE;
}
if (element->getAttr(txXSLTAtoms::perMille,
kNameSpaceID_None, attValue)) {
if (attValue.length() == 1)
format->mPerMille = attValue.charAt(0);
else if (!attValue.isEmpty())
success = MB_FALSE;
}
if (element->getAttr(txXSLTAtoms::zeroDigit,
kNameSpaceID_None, attValue)) {
if (attValue.length() == 1)
format->mZeroDigit = attValue.charAt(0);
else if (!attValue.isEmpty())
success = MB_FALSE;
}
if (element->getAttr(txXSLTAtoms::digit, kNameSpaceID_None,
attValue)) {
if (attValue.length() == 1)
format->mDigit = attValue.charAt(0);
else
success = MB_FALSE;
}
if (element->getAttr(txXSLTAtoms::patternSeparator,
kNameSpaceID_None, attValue)) {
if (attValue.length() == 1)
format->mPatternSeparator = attValue.charAt(0);
else
success = MB_FALSE;
}
if (!success) {
delete format;
return MB_FALSE;
}
// Does an existing format with that name exist?
// (name="" means default format)
txDecimalFormat* existing = NULL;
if (defaultDecimalFormatSet || !formatName.isEmpty()) {
existing = (txDecimalFormat*)decimalFormats.get(formatName);
}
else {
// We are overriding the predefined default format which is always
// allowed
delete decimalFormats.remove(formatName);
defaultDecimalFormatSet = MB_TRUE;
}
if (existing) {
success = existing->isEqual(format);
delete format;
}
else {
decimalFormats.put(formatName, format);
}
return success;
}
/*
* Returns a decimal format or NULL if no such format exists.
*/
txDecimalFormat* ProcessorState::getDecimalFormat(String& name)
{
return (txDecimalFormat*)decimalFormats.get(name);
}
//--------------------------------------------------/
//- Virtual Methods from derived from ContextState -/
//--------------------------------------------------/
/**
* Returns the Stack of context NodeSets
* @return the Stack of context NodeSets
**/
Stack* ProcessorState::getNodeSetStack() {
return &nodeSetStack;
} //-- getNodeSetStack
/**
* Returns the value of a given variable binding within the current scope
* @param the name to which the desired variable value has been bound
* @return the ExprResult which has been bound to the variable with the given
* name
**/
ExprResult* ProcessorState::getVariable(String& name) {
StackIterator* iter = variableSets.iterator();
ExprResult* exprResult = 0;
while (iter->hasNext()) {
NamedMap* map = (NamedMap*) iter->next();
if (map->get(name)) {
exprResult = ((VariableBinding*)map->get(name))->getValue();
break;
}
}
delete iter;
return exprResult;
} //-- getVariable
/**
* Determines if the given XML node allows Whitespace stripping
**/
MBool ProcessorState::isStripSpaceAllowed(Node* node)
{
if (!node)
return MB_FALSE;
switch (node->getNodeType()) {
case Node::ELEMENT_NODE:
{
// check Whitespace stipping handling list against given Node
ImportFrame* frame;
txListIterator frameIter(&mImportFrames);
String name = node->getNodeName();
while ((frame = (ImportFrame*)frameIter.next())) {
txListIterator iter(&frame->mWhiteNameTests);
while (iter.hasNext()) {
txNameTestItem* iNameTest = (txNameTestItem*)iter.next();
if (iNameTest->matches(node, this))
return iNameTest->stripsSpace();
}
}
if (mOutputFormat.mMethod == eHTMLOutput) {
String ucName = name;
ucName.toUpperCase();
if (ucName.isEqual("SCRIPT"))
return MB_FALSE;
}
break;
}
case Node::TEXT_NODE:
case Node::CDATA_SECTION_NODE:
{
if (!XMLUtils::shouldStripTextnode(node->getNodeValue()))
return MB_FALSE;
return isStripSpaceAllowed(node->getParentNode());
}
case Node::DOCUMENT_NODE:
{
return MB_TRUE;
}
}
XMLSpaceMode mode = getXMLSpaceMode(node);
if (mode == DEFAULT)
return MB_FALSE;
return (MBool)(STRIP == mode);
}
/**
* Notifies this Error observer of a new error, with default
* level of NORMAL
**/
void ProcessorState::recieveError(String& errorMessage) {
recieveError(errorMessage, ErrorObserver::NORMAL);
} //-- recieveError
/**
* Notifies this Error observer of a new error using the given error level
**/
void ProcessorState::recieveError(String& errorMessage, ErrorLevel level) {
ListIterator* iter = errorObservers.iterator();
while (iter->hasNext()) {
ErrorObserver* observer = (ErrorObserver*)iter->next();
observer->recieveError(errorMessage, level);
}
delete iter;
} //-- recieveError
/**
* Returns a call to the function that has the given name.
* This method is used for XPath Extension Functions.
* @return the FunctionCall for the function with the given name.
**/
FunctionCall* ProcessorState::resolveFunctionCall(const String& name) {
String err;
if (DOCUMENT_FN.isEqual(name)) {
return new DocumentFunctionCall(this, mXPathParseContext);
}
else if (KEY_FN.isEqual(name)) {
return new txKeyFunctionCall(this);
}
else if (FORMAT_NUMBER_FN.isEqual(name)) {
return new txFormatNumberFunctionCall(this);
}
else if (CURRENT_FN.isEqual(name)) {
return new CurrentFunctionCall(this);
}
else if (UNPARSED_ENTITY_URI_FN.isEqual(name)) {
err = "function not yet implemented: ";
err.append(name);
}
else if (GENERATE_ID_FN.isEqual(name)) {
return new GenerateIdFunctionCall();
}
else if (SYSTEM_PROPERTY_FN.isEqual(name)) {
return new SystemPropertyFunctionCall();
}
else if (ELEMENT_AVAILABLE_FN.isEqual(name)) {
return new ElementAvailableFunctionCall();
}
else if (FUNCTION_AVAILABLE_FN.isEqual(name)) {
return new FunctionAvailableFunctionCall();
}
else {
err = "invalid function call: ";
err.append(name);
}
return new ErrorFunctionCall(err);
} //-- resolveFunctionCall
//-------------------/
//- Private Methods -/
//-------------------/
/*
* Returns the closest xml:space value for the given Text node
*/
ProcessorState::XMLSpaceMode ProcessorState::getXMLSpaceMode(Node* aNode)
{
NS_ASSERTION(aNode, "Calling getXMLSpaceMode with NULL node!");
Node* parent = aNode;
while (parent) {
switch (parent->getNodeType()) {
case Node::ELEMENT_NODE:
{
String value;
((Element*)parent)->getAttr(txXMLAtoms::space,
kNameSpaceID_XML, value);
if (value.isEqual(PRESERVE_VALUE))
return PRESERVE;
break;
}
case Node::TEXT_NODE:
case Node::CDATA_SECTION_NODE:
{
// We will only see this the first time through the loop
// if the argument node is a text node.
break;
}
default:
{
return DEFAULT;
}
}
parent = parent->getParentNode();
}
return DEFAULT;
}
/**
* Initializes this ProcessorState
**/
void ProcessorState::initialize()
{
// add global variable set
NamedMap* globalVars = new NamedMap();
globalVars->setObjectDeletion(MB_TRUE);
variableSets.push(globalVars);
/* turn object deletion on for some of the Maps (NamedMap) */
mExprHashes[SelectAttr].setOwnership(Map::eOwnsItems);
mExprHashes[TestAttr].setOwnership(Map::eOwnsItems);
mExprHashes[ValueAttr].setOwnership(Map::eOwnsItems);
mPatternHashes[CountAttr].setOwnership(Map::eOwnsItems);
mPatternHashes[FromAttr].setOwnership(Map::eOwnsItems);
// determine xslt properties
if (mSourceDocument) {
loadedDocuments.put(mSourceDocument->getBaseURI(), mSourceDocument);
}
if (xslDocument) {
loadedDocuments.put(xslDocument->getBaseURI(), xslDocument);
// XXX hackarond to get namespacehandling in a little better shape
// we won't need to do this once we resolve namespaces during parsing
mXPathParseContext = xslDocument->getDocumentElement();
}
// make sure all keys are deleted
xslKeys.setObjectDeletion(MB_TRUE);
// Make sure all loaded documents get deleted
loadedDocuments.setObjectDeletion(MB_TRUE);
// add predefined default decimal format
defaultDecimalFormatSet = MB_FALSE;
decimalFormats.put("", new txDecimalFormat);
decimalFormats.setObjectDeletion(MB_TRUE);
}
ProcessorState::ImportFrame::ImportFrame(ImportFrame* aFirstNotImported)
{
mNamedAttributeSets.setObjectDeletion(MB_TRUE);
mFirstNotImported = aFirstNotImported;
}
ProcessorState::ImportFrame::~ImportFrame()
{
// Delete all txNameTestItems
txListIterator whiteIter(&mWhiteNameTests);
while (whiteIter.hasNext())
delete (txNameTestItem*)whiteIter.next();
// Delete templates in mMatchableTemplates
StringList* templKeys = mMatchableTemplates.keys();
if (templKeys) {
StringListIterator keysIter(templKeys);
String* key;
while ((key = keysIter.next())) {
txList* templList = (txList*)mMatchableTemplates.get(*key);
txListIterator templIter(templList);
MatchableTemplate* templ;
while ((templ = (MatchableTemplate*)templIter.next())) {
delete templ->mMatch;
delete templ;
}
delete templList;
}
}
delete templKeys;
}