зеркало из https://github.com/mozilla/pjs.git
Implement <xsl:key> and the key() xslt function. Also extend the Map class to enable it to own either it's key-objects or it's value-objects, not just both.
b=65986, r=peterv,pike sr=jst
This commit is contained in:
Родитель
335c7199f4
Коммит
f96040673d
|
@ -121,6 +121,7 @@ LOBJS =../source/base/ArrayList.o \
|
|||
../source/xslt/functions/ElementAvailableFnCall.o \
|
||||
../source/xslt/functions/FunctionAvailableFnCall.o \
|
||||
../source/xslt/functions/GenerateIdFunctionCall.o \
|
||||
../source/xslt/functions/txKeyFunctionCall.o \
|
||||
../source/xslt/functions/SystemPropertyFunctionCall.o \
|
||||
../source/xslt/util/NodeSorter.o \
|
||||
../source/xslt/util/NodeStack.o \
|
||||
|
|
|
@ -116,6 +116,7 @@ CPP_OBJS= \
|
|||
..\source\xslt\functions\$(OBJDIR)\ElementAvailableFnCall.obj \
|
||||
..\source\xslt\functions\$(OBJDIR)\FunctionAvailableFnCall.obj \
|
||||
..\source\xslt\functions\$(OBJDIR)\GenerateIdFunctionCall.obj \
|
||||
..\source\xslt\functions\$(OBJDIR)\txKeyFunctionCall.obj \
|
||||
..\source\xslt\functions\$(OBJDIR)\SystemPropertyFunctionCall.obj \
|
||||
..\source\xslt\util\$(OBJDIR)\NodeSorter.obj \
|
||||
..\source\xslt\util\$(OBJDIR)\NodeStack.obj \
|
||||
|
|
|
@ -20,12 +20,12 @@
|
|||
* Keith Visco, kvisco@ziplink.net
|
||||
* -- original author.
|
||||
*
|
||||
* $Id: Map.cpp,v 1.2 2000-06-11 12:21:13 Peter.VanderBeken%pandora.be Exp $
|
||||
* $Id: Map.cpp,v 1.3 2001-06-26 11:58:46 sicking%bigfoot.com Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* A Hashtable for TxObjects
|
||||
* @version $Revision: 1.2 $ $Date: 2000-06-11 12:21:13 $
|
||||
* @version $Revision: 1.3 $ $Date: 2001-06-26 11:58:46 $
|
||||
*/
|
||||
|
||||
|
||||
|
@ -62,7 +62,7 @@ void Map::initialize(Int32 size) {
|
|||
|
||||
//-- by default the Map will not delete it's
|
||||
//-- object references
|
||||
doObjectDeletion = MB_FALSE;
|
||||
mOwnership = eOwnsNone;
|
||||
|
||||
//-- create a new array of bucket pointers
|
||||
elements = new BucketItem*[size];
|
||||
|
@ -85,20 +85,10 @@ Map::~Map() {
|
|||
|
||||
|
||||
/**
|
||||
* Removes all elements from the Map. If the object deletion flag
|
||||
* has been set to true (by a call to setObjectDeletion) objects
|
||||
* will also be deleted as they are removed from the map
|
||||
* Removes all elements from the Map. Deletes objects according
|
||||
* to the mOwnership attribute
|
||||
**/
|
||||
void Map::clear() {
|
||||
clear(doObjectDeletion);
|
||||
} //-- clear
|
||||
|
||||
/**
|
||||
* Removes all elements from the Map
|
||||
* @param deleteObjects a flag indicating whether or not to delete the
|
||||
* objects and keys currently in the map
|
||||
**/
|
||||
void Map::clear(MBool deleteObjects) {
|
||||
|
||||
for (int i = 0; i < numberOfBuckets; i++) {
|
||||
|
||||
|
@ -106,15 +96,10 @@ void Map::clear(MBool deleteObjects) {
|
|||
while (bktItem) {
|
||||
BucketItem* tItem = bktItem;
|
||||
bktItem = bktItem->next;
|
||||
//-- repoint item to 0 to prevent deletion
|
||||
if ( ! deleteObjects ) {
|
||||
tItem->item = 0;
|
||||
tItem->key = 0;
|
||||
}
|
||||
else {
|
||||
if (mOwnership & eOwnsItems)
|
||||
delete tItem->item;
|
||||
if (mOwnership & eOwnsKeys)
|
||||
delete tItem->key;
|
||||
}
|
||||
//--delete tItem;
|
||||
delete tItem;
|
||||
}
|
||||
|
@ -239,13 +224,11 @@ TxObject* Map::remove(TxObject* key) {
|
|||
} //-- remove
|
||||
|
||||
/**
|
||||
* Sets the object deletion flag. If set to true, objects, including
|
||||
* keys, in the Map will be deleted upon calling the clear() method, or
|
||||
* upon destruction. By default this is false.
|
||||
* Sets the ownership flag.
|
||||
**/
|
||||
void Map::setObjectDeletion(MBool deleteObjects) {
|
||||
doObjectDeletion = deleteObjects;
|
||||
} //-- setObjectDeletion
|
||||
void Map::setOwnership(txMapOwnership aOwnership) {
|
||||
mOwnership = aOwnership;
|
||||
} //-- setOwnership
|
||||
|
||||
/**
|
||||
* Returns the number of key-object pairs in the Map
|
||||
|
|
|
@ -20,12 +20,12 @@
|
|||
* Keith Visco, kvisco@ziplink.net
|
||||
* -- original author.
|
||||
*
|
||||
* $Id: Map.h,v 1.1 2000-04-12 10:49:40 kvisco%ziplink.net Exp $
|
||||
* $Id: Map.h,v 1.2 2001-06-26 11:58:47 sicking%bigfoot.com Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* A Hashtable for TxObjects
|
||||
* @version $Revision: 1.1 $ $Date: 2000-04-12 10:49:40 $
|
||||
* @version $Revision: 1.2 $ $Date: 2001-06-26 11:58:47 $
|
||||
*/
|
||||
|
||||
#ifndef TRANSFRMX_MAP_H
|
||||
|
@ -81,32 +81,41 @@ public:
|
|||
void put(TxObject* key, TxObject* obj);
|
||||
|
||||
/**
|
||||
* Removes all elements from the Map table
|
||||
* enum used when setting ownership
|
||||
**/
|
||||
enum txMapOwnership
|
||||
{
|
||||
eOwnsNone = 0x00,
|
||||
eOwnsItems = 0x01,
|
||||
eOwnsKeys = 0x02,
|
||||
eOwnsKeysAndItems = eOwnsItems | eOwnsKeys
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes all elements from the Map. Deletes objects according
|
||||
* to the mOwnership attribute
|
||||
**/
|
||||
void clear();
|
||||
|
||||
void clear(MBool doObjectDeletion);
|
||||
|
||||
/**
|
||||
* Returns true if there are no elements in this Map
|
||||
* @return true if there are no elements in this Map.
|
||||
**/
|
||||
MBool isEmpty();
|
||||
|
||||
/**
|
||||
* Removes the object associated with the given key from this Map
|
||||
* @param key the TxObject used to compute the hashCode for the object to remove
|
||||
* from the Map
|
||||
* @return the removed object
|
||||
**/
|
||||
// THIS IS DEPRECATED
|
||||
TxObject* remove(TxObject* key);
|
||||
|
||||
// THIS IS DEPRECATED, use setOwnership
|
||||
void setObjectDeletion(MBool deleteObjects)
|
||||
{
|
||||
setOwnership(deleteObjects ? eOwnsKeysAndItems : eOwnsNone );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the object deletion flag. If set to true, objects in
|
||||
* the Map will be deleted upon calling the clear() method, or
|
||||
* upon destruction. By default this is false.
|
||||
* Sets the ownership attribute.
|
||||
**/
|
||||
void setObjectDeletion(MBool deleteObjects);
|
||||
void setOwnership(txMapOwnership aOwnership);
|
||||
|
||||
/**
|
||||
* Returns the number of key-element pairs in the Map
|
||||
|
@ -135,7 +144,12 @@ private:
|
|||
|
||||
Int32 numberOfBuckets;
|
||||
Int32 numberOfElements;
|
||||
MBool doObjectDeletion;
|
||||
|
||||
/**
|
||||
* The ownership flag. Used to decide which objects are
|
||||
* owned by the map and thus should be deleted when released
|
||||
**/
|
||||
txMapOwnership mOwnership;
|
||||
|
||||
//-------------------/
|
||||
//- Private Methods -/
|
||||
|
|
|
@ -117,6 +117,7 @@ OBJS =../base/ArrayList.o \
|
|||
../xslt/functions/ElementAvailableFnCall.o \
|
||||
../xslt/functions/FunctionAvailableFnCall.o \
|
||||
../xslt/functions/GenerateIdFunctionCall.o \
|
||||
../xslt/functions/txKeyFunctionCall.o \
|
||||
../xslt/functions/SystemPropertyFunctionCall.o \
|
||||
../xslt/util/NodeSorter.o \
|
||||
../xslt/util/NodeStack.o \
|
||||
|
|
|
@ -111,6 +111,7 @@ CPP_OBJS= \
|
|||
../xslt/functions/$(OBJDIR)/ElementAvailableFnCall.obj \
|
||||
../xslt/functions/$(OBJDIR)/FunctionAvailableFnCall.obj \
|
||||
../xslt/functions/$(OBJDIR)/GenerateIdFunctionCall.obj \
|
||||
../xslt/functions/$(OBJDIR)/txKeyFunctionCall.obj \
|
||||
../xslt/functions/$(OBJDIR)/SystemPropertyFunctionCall.obj \
|
||||
../xslt/util/$(OBJDIR)/NodeSorter.obj \
|
||||
../xslt/util/$(OBJDIR)/NodeStack.obj \
|
||||
|
|
|
@ -28,14 +28,14 @@
|
|||
* W3C XPath 1.0 Recommendation
|
||||
* -- Added lang attr declaration
|
||||
*
|
||||
* $Id: Names.cpp,v 1.10 2001-05-12 12:00:11 peterv%netscape.com Exp $
|
||||
* $Id: Names.cpp,v 1.11 2001-06-26 11:58:51 sicking%bigfoot.com Exp $
|
||||
*/
|
||||
|
||||
/**
|
||||
* XSL names used throughout the XSLProcessor.
|
||||
* Probably should be wrapped in a Namespace
|
||||
* @author <a href="mailto:kvisco@ziplink.net">Keith Visco</a>
|
||||
* @version $Revision: 1.10 $ $Date: 2001-05-12 12:00:11 $
|
||||
* @version $Revision: 1.11 $ $Date: 2001-06-26 11:58:51 $
|
||||
**/
|
||||
#include "Names.h"
|
||||
|
||||
|
@ -63,6 +63,7 @@ const String FOR_EACH = "for-each";
|
|||
const String IF = "if";
|
||||
const String IMPORT = "import";
|
||||
const String INCLUDE = "include";
|
||||
const String KEY = "key";
|
||||
const String MESSAGE = "message";
|
||||
const String NUMBER = "number";
|
||||
const String OTHERWISE = "otherwise";
|
||||
|
@ -106,6 +107,7 @@ const String PRIORITY_ATTR = "priority";
|
|||
const String SELECT_ATTR = "select";
|
||||
const String STANDALONE = "standalone";
|
||||
const String TEST_ATTR = "test";
|
||||
const String USE_ATTR = "use";
|
||||
const String USE_ATTRIBUTE_SETS_ATTR = "use-attribute-sets";
|
||||
const String VALUE_ATTR = "value";
|
||||
const String VERSION_ATTR = "version";
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
* W3C XPath 1.0 Recommendation
|
||||
* -- Added lang attr declaration
|
||||
|
||||
* $Id: Names.h,v 1.9 2001-05-12 12:00:17 peterv%netscape.com Exp $
|
||||
* $Id: Names.h,v 1.10 2001-06-26 11:58:51 sicking%bigfoot.com Exp $
|
||||
*/
|
||||
|
||||
#ifndef TRANSFRMX_NAMES_H
|
||||
|
@ -59,6 +59,7 @@ extern const String FOR_EACH;
|
|||
extern const String IF;
|
||||
extern const String IMPORT;
|
||||
extern const String INCLUDE;
|
||||
extern const String KEY;
|
||||
extern const String MESSAGE;
|
||||
extern const String NUMBER;
|
||||
extern const String OTHERWISE;
|
||||
|
@ -103,6 +104,7 @@ extern const String PRIORITY_ATTR;
|
|||
extern const String SELECT_ATTR;
|
||||
extern const String STANDALONE;
|
||||
extern const String TEST_ATTR;
|
||||
extern const String USE_ATTR;
|
||||
extern const String USE_ATTRIBUTE_SETS_ATTR;
|
||||
extern const String VALUE_ATTR;
|
||||
extern const String VERSION_ATTR;
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
/**
|
||||
* Implementation of ProcessorState
|
||||
* Much of this code was ported from XSL:P
|
||||
* @version $Revision: 1.31 $ $Date: 2001-06-20 07:07:09 $
|
||||
* @version $Revision: 1.32 $ $Date: 2001-06-26 11:58:51 $
|
||||
**/
|
||||
|
||||
#include "ProcessorState.h"
|
||||
|
@ -682,6 +682,32 @@ Document* ProcessorState::getLoadedDocument(String& url) {
|
|||
return (Document*) loadedDocuments.get(docUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the supplied xsl:key to the set of keys
|
||||
**/
|
||||
MBool ProcessorState::addKey(Element* keyElem) {
|
||||
String keyName = keyElem->getAttribute(NAME_ATTR);
|
||||
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);
|
||||
}
|
||||
|
||||
return xslKey->addKey(keyElem->getAttribute(MATCH_ATTR), keyElem->getAttribute(USE_ATTR));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
//--------------------------------------------------/
|
||||
//- Virtual Methods from derived from ContextState -/
|
||||
//--------------------------------------------------/
|
||||
|
@ -799,8 +825,7 @@ FunctionCall* ProcessorState::resolveFunctionCall(const String& name) {
|
|||
return new DocumentFunctionCall(this, xslDocument);
|
||||
}
|
||||
else if (KEY_FN.isEqual(name)) {
|
||||
err = "function not yet implemented: ";
|
||||
err.append(name);
|
||||
return new txKeyFunctionCall(this);
|
||||
}
|
||||
else if (FORMAT_NUMBER_FN.isEqual(name)) {
|
||||
err = "function not yet implemented: ";
|
||||
|
@ -999,6 +1024,9 @@ void ProcessorState::initialize() {
|
|||
} //-- end if atts are not null
|
||||
}
|
||||
|
||||
//-- make sure all keys are deleted
|
||||
xslKeys.setObjectDeletion(MB_TRUE);
|
||||
|
||||
//-- Make sure all loaded documents get deleted
|
||||
loadedDocuments.setObjectDeletion(MB_TRUE);
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
* Keith Visco, kvisco@ziplink.net
|
||||
* -- original author.
|
||||
*
|
||||
* $Id: ProcessorState.h,v 1.14 2001-06-20 07:07:11 sicking%bigfoot.com Exp $
|
||||
* $Id: ProcessorState.h,v 1.15 2001-06-26 11:58:52 sicking%bigfoot.com Exp $
|
||||
*/
|
||||
|
||||
|
||||
|
@ -40,10 +40,12 @@
|
|||
#include "StringList.h"
|
||||
#include "OutputFormat.h"
|
||||
|
||||
class txXSLKey;
|
||||
|
||||
/**
|
||||
* Class used for keeping the current state of the XSL Processor
|
||||
* @author <a href="mailto:kvisco@ziplink.net">Keith Visco</a>
|
||||
* @version $Revision: 1.14 $ $Date: 2001-06-20 07:07:11 $
|
||||
* @version $Revision: 1.15 $ $Date: 2001-06-26 11:58:52 $
|
||||
**/
|
||||
class ProcessorState : public ContextState {
|
||||
|
||||
|
@ -252,6 +254,17 @@ public:
|
|||
**/
|
||||
Document* getLoadedDocument(String& url);
|
||||
|
||||
/**
|
||||
* Adds the supplied xsl:key to the set of keys
|
||||
**/
|
||||
MBool addKey(Element* xslKey);
|
||||
|
||||
/**
|
||||
* Returns the key with the supplied name
|
||||
* returns NULL if no such key exists
|
||||
**/
|
||||
txXSLKey* getKey(String& keyName);
|
||||
|
||||
//-------------------------------------/
|
||||
//- Virtual Methods from ContextState -/
|
||||
//-------------------------------------/
|
||||
|
@ -399,6 +412,11 @@ private:
|
|||
* the set of loaded documents
|
||||
**/
|
||||
NamedMap loadedDocuments;
|
||||
|
||||
/**
|
||||
* The set of all available keys
|
||||
**/
|
||||
NamedMap xslKeys;
|
||||
|
||||
|
||||
XSLTAction* currentAction;
|
||||
|
|
|
@ -73,7 +73,7 @@
|
|||
/**
|
||||
* XSLTProcessor is a class for Processing XSL stylesheets
|
||||
* @author <a href="mailto:kvisco@ziplink.net">Keith Visco</a>
|
||||
* @version $Revision: 1.58 $ $Date: 2001-06-21 08:24:58 $
|
||||
* @version $Revision: 1.59 $ $Date: 2001-06-26 11:58:52 $
|
||||
**/
|
||||
|
||||
/**
|
||||
|
@ -111,6 +111,7 @@ XSLTProcessor::XSLTProcessor() {
|
|||
xslTypes.put(FOR_EACH, new XSLType(XSLType::FOR_EACH));
|
||||
xslTypes.put(IF, new XSLType(XSLType::IF));
|
||||
xslTypes.put(INCLUDE, new XSLType(XSLType::INCLUDE));
|
||||
xslTypes.put(KEY, new XSLType(XSLType::KEY));
|
||||
xslTypes.put(MESSAGE, new XSLType(XSLType::MESSAGE));
|
||||
xslTypes.put(NUMBER, new XSLType(XSLType::NUMBER));
|
||||
xslTypes.put(OTHERWISE, new XSLType(XSLType::OTHERWISE));
|
||||
|
@ -481,6 +482,17 @@ void XSLTProcessor::processTopLevel(Document* aSource,
|
|||
}
|
||||
break;
|
||||
|
||||
}
|
||||
case XSLType::KEY :
|
||||
{
|
||||
if (!aPs->addKey(element)) {
|
||||
String err("error adding key '");
|
||||
err.append(element->getAttribute(NAME_ATTR));
|
||||
err.append("'");
|
||||
notifyError(err);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
case XSLType::OUTPUT :
|
||||
{
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
/**
|
||||
* A class for Processing XSL Stylesheets
|
||||
* @author <a href="mailto:kvisco@ziplink.net">Keith Visco</a>
|
||||
* @version $Revision: 1.23 $ $Date: 2001-06-20 07:07:14 $
|
||||
* @version $Revision: 1.24 $ $Date: 2001-06-26 11:58:53 $
|
||||
**/
|
||||
class XSLTProcessor
|
||||
#ifndef TX_EXE
|
||||
|
@ -378,6 +378,7 @@ public:
|
|||
ELEMENT,
|
||||
IF,
|
||||
INCLUDE,
|
||||
KEY,
|
||||
FOR_EACH,
|
||||
LITERAL,
|
||||
NUMBER,
|
||||
|
|
|
@ -81,6 +81,7 @@ ExprResult* ElementAvailableFunctionCall::evaluate(Node* context, ContextState*
|
|||
localName.isEqual(IF) ||
|
||||
localName.isEqual(IMPORT) ||
|
||||
localName.isEqual(INCLUDE) ||
|
||||
localName.isEqual(KEY) ||
|
||||
localName.isEqual(MESSAGE) ||
|
||||
localName.isEqual(NUMBER) ||
|
||||
localName.isEqual(OTHERWISE) ||
|
||||
|
|
|
@ -91,9 +91,9 @@ ExprResult* FunctionAvailableFunctionCall::evaluate(Node* context, ContextState*
|
|||
property.isEqual(XPathNames::CEILING_FN) ||
|
||||
property.isEqual(XPathNames::FLOOR_FN) ||
|
||||
property.isEqual(DOCUMENT_FN) ||
|
||||
// property.isEqual(KEY_FN) ||
|
||||
property.isEqual(KEY_FN) ||
|
||||
// property.isEqual(FORMAT_NUMBER_FN) ||
|
||||
// property.isEqual(CURRENT_FN) ||
|
||||
property.isEqual(CURRENT_FN) ||
|
||||
// property.isEqual(UNPARSED_ENTITY_URI_FN) ||
|
||||
property.isEqual(GENERATE_ID_FN) ||
|
||||
property.isEqual(SYSTEM_PROPERTY_FN) ||
|
||||
|
|
|
@ -36,6 +36,7 @@ CPPSRCS = CurrentFunctionCall.cpp \
|
|||
ElementAvailableFnCall.cpp \
|
||||
FunctionAvailableFnCall.cpp \
|
||||
GenerateIdFunctionCall.cpp \
|
||||
txKeyFunctionCall.cpp \
|
||||
SystemPropertyFunctionCall.cpp
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -23,7 +23,10 @@
|
|||
* Olivier Gerardin,
|
||||
* -- added document() function definition
|
||||
*
|
||||
* $Id: XSLTFunctions.h,v 1.6 2001-04-08 14:37:13 peterv%netscape.com Exp $
|
||||
* Jonas Sicking,
|
||||
* -- added txXSLKey class
|
||||
*
|
||||
* $Id: XSLTFunctions.h,v 1.7 2001-06-26 11:58:56 sicking%bigfoot.com Exp $
|
||||
*/
|
||||
|
||||
#ifndef TRANSFRMX_XSLT_FUNCTIONS_H
|
||||
|
@ -34,6 +37,8 @@
|
|||
#include "DOMHelper.h"
|
||||
#include "TxString.h"
|
||||
#include "ProcessorState.h"
|
||||
#include "Map.h"
|
||||
#include "List.h"
|
||||
|
||||
/**
|
||||
* The definition for the XSLT document() function
|
||||
|
@ -63,29 +68,118 @@ private:
|
|||
ProcessorState* processorState;
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* The definition for the XSLT key() function
|
||||
**/
|
||||
class KeyFunctionCall : public FunctionCall {
|
||||
*/
|
||||
class txKeyFunctionCall : public FunctionCall {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
/*
|
||||
* Creates a new key() function call
|
||||
**/
|
||||
KeyFunctionCall();
|
||||
*/
|
||||
txKeyFunctionCall(ProcessorState* aPs);
|
||||
|
||||
/**
|
||||
* Evaluates this Expr based on the given context node and processor state
|
||||
* @param context the context node for evaluation of this Expr
|
||||
* @param cs the ContextState containing the stack information needed
|
||||
* for evaluation
|
||||
/*
|
||||
* Evaluates a key() xslt-functioncall. First argument is name of key
|
||||
* to use, second argument is value to look up.
|
||||
* @param aContext the context node for evaluation of this Expr
|
||||
* @param aCs the ContextState containing the stack information needed
|
||||
* for evaluation
|
||||
* @return the result of the evaluation
|
||||
* @see FunctionCall.h
|
||||
**/
|
||||
virtual ExprResult* evaluate(Node* context, ContextState* cs);
|
||||
*/
|
||||
virtual ExprResult* evaluate(Node* aContext, ContextState* aCs);
|
||||
|
||||
private:
|
||||
ProcessorState* mProcessorState;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class representing an <xsl:key>. Or in the case where several <xsl:key>s
|
||||
* have the same name one object represents all <xsl:key>s with that name
|
||||
*/
|
||||
class txXSLKey : public TxObject {
|
||||
|
||||
public:
|
||||
txXSLKey(ProcessorState* aPs);
|
||||
~txXSLKey();
|
||||
|
||||
/*
|
||||
* Returns a NodeSet containing all nodes within the specified document
|
||||
* that have the value keyValue. The document is indexed in case it
|
||||
* hasn't been searched previously. The returned nodeset is owned by
|
||||
* the txXSLKey object
|
||||
* @param aKeyValue Value to search for
|
||||
* @param aDoc Document to search in
|
||||
* @return a NodeSet* containing all nodes in doc matching with value
|
||||
* keyValue
|
||||
*/
|
||||
const NodeSet* getNodes(String& aKeyValue, Document* aDoc);
|
||||
|
||||
/*
|
||||
* Adds a match/use pair. Returns MB_FALSE if matchString or useString
|
||||
* can't be parsed.
|
||||
* @param aMatchString String to be parsed as match-pattern
|
||||
* @param aUseString String to be parsed as use-expression
|
||||
* @return MB_FALSE if matchString or useString can't be parsed
|
||||
* MB_TRUE otherwise
|
||||
*/
|
||||
MBool addKey(const String& aMatchString, const String& aUseString);
|
||||
|
||||
private:
|
||||
/*
|
||||
* Indexes a document and adds it to the set of indexed documents
|
||||
* @param aDoc Document to index and add
|
||||
* @returns a NamedMap* containing the index
|
||||
*/
|
||||
NamedMap* addDocument(Document* aDoc);
|
||||
|
||||
/*
|
||||
* Recursively searches a node, its attributes and its subtree for
|
||||
* nodes matching any of the keys match-patterns.
|
||||
* @param aNode node to search
|
||||
* @param aMap index to add search result in
|
||||
*/
|
||||
void indexTree(Node* aNode, NamedMap* aMap);
|
||||
|
||||
/*
|
||||
* Tests one node if it matches any of the keys match-patterns. If
|
||||
* the node matches its values are added to the index.
|
||||
* @param aNode node to test
|
||||
* @param aMap index to add values to
|
||||
*/
|
||||
void testNode(Node* aNode, NamedMap* aMap);
|
||||
|
||||
/*
|
||||
* represents one match/use pair
|
||||
*/
|
||||
struct Key {
|
||||
Pattern* matchPattern;
|
||||
Expr* useExpr;
|
||||
};
|
||||
|
||||
/*
|
||||
* List of all match/use pairs
|
||||
*/
|
||||
List mKeys;
|
||||
|
||||
/*
|
||||
* Map containing all indexes (keyed on document). Every index is a
|
||||
* NamedMap. Every NamedMap contains NodeLists with the nodes for
|
||||
* a certain value
|
||||
*/
|
||||
Map mMaps;
|
||||
|
||||
/*
|
||||
* ProcessorState used to parse the match-patterns and
|
||||
* use-expressions
|
||||
*/
|
||||
ProcessorState* mProcessorState;
|
||||
|
||||
/*
|
||||
* Used to return empty nodeset
|
||||
*/
|
||||
NodeSet mEmptyNodeset;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -32,6 +32,7 @@ CPPSRCS= \
|
|||
ElementAvailableFnCall.cpp \
|
||||
FunctionAvailableFnCall.cpp \
|
||||
GenerateIDFunctionCall.cpp \
|
||||
txKeyFunctionCall.cpp \
|
||||
SystemPropertyFunctionCall.cpp \
|
||||
$(NULL)
|
||||
|
||||
|
@ -41,6 +42,7 @@ CPP_OBJS= \
|
|||
.\$(OBJDIR)\ElementAvailableFnCall.obj \
|
||||
.\$(OBJDIR)\FunctionAvailableFnCall.obj \
|
||||
.\$(OBJDIR)\GenerateIDFunctionCall.obj \
|
||||
.\$(OBJDIR)\txKeyFunctionCall.obj \
|
||||
.\$(OBJDIR)\SystemPropertyFunctionCall.obj \
|
||||
$(NULL)
|
||||
|
||||
|
|
|
@ -0,0 +1,257 @@
|
|||
/* -*- 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 Initial Developer of the Original Code is Jonas Sicking.
|
||||
* Portions created by Jonas Sicking are Copyright (C) 2001, Jonas Sicking.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Jonas Sicking, sicking@bigfoot.com
|
||||
* -- original author.
|
||||
*/
|
||||
|
||||
#include "XSLTFunctions.h"
|
||||
#include "Names.h"
|
||||
#include "XMLDOMUtils.h"
|
||||
|
||||
/*
|
||||
* txKeyFunctionCall
|
||||
* A representation of the XSLT additional function: key()
|
||||
*/
|
||||
|
||||
/*
|
||||
* Creates a new key function call
|
||||
*/
|
||||
txKeyFunctionCall::txKeyFunctionCall(ProcessorState* aPs) :
|
||||
FunctionCall(KEY_FN)
|
||||
{
|
||||
mProcessorState = aPs;
|
||||
}
|
||||
|
||||
/*
|
||||
* Evaluates a key() xslt-function call. First argument is name of key
|
||||
* to use, second argument is value to look up.
|
||||
* @param aContext the context node for evaluation of this Expr
|
||||
* @param aCs the ContextState containing the stack information needed
|
||||
* for evaluation
|
||||
* @return the result of the evaluation
|
||||
*/
|
||||
ExprResult* txKeyFunctionCall::evaluate(Node* aContext, ContextState* aCs)
|
||||
{
|
||||
NodeSet* res = new NodeSet;
|
||||
if (!res) {
|
||||
// ErrorReport: out of memory
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!requireParams(2, 2, aCs))
|
||||
return res;
|
||||
|
||||
ListIterator iter(¶ms);
|
||||
String keyName;
|
||||
evaluateToString((Expr*)iter.next(), aContext, aCs, keyName);
|
||||
Expr* param = (Expr*) iter.next();
|
||||
|
||||
txXSLKey* key = mProcessorState->getKey(keyName);
|
||||
if (!key) {
|
||||
String err("No key with that name in: ");
|
||||
toString(err);
|
||||
aCs->recieveError(err);
|
||||
return res;
|
||||
}
|
||||
|
||||
ExprResult* exprResult = param->evaluate(aContext, aCs);
|
||||
if (!exprResult)
|
||||
return res;
|
||||
|
||||
if (exprResult->getResultType() == ExprResult::NODESET) {
|
||||
NodeSet* nodeSet = (NodeSet*) exprResult;
|
||||
for (int i=0; i<nodeSet->size(); i++) {
|
||||
String val;
|
||||
XMLDOMUtils::getNodeValue(nodeSet->get(i), &val);
|
||||
key->getNodes(val,aContext->getOwnerDocument())->copyInto(*res);
|
||||
}
|
||||
}
|
||||
else {
|
||||
String val;
|
||||
exprResult->stringValue(val);
|
||||
key->getNodes(val,aContext->getOwnerDocument())->copyInto(*res);
|
||||
}
|
||||
delete exprResult;
|
||||
return res;
|
||||
|
||||
} // evaluate
|
||||
|
||||
/*
|
||||
* Class representing an <xsl:key>. Or in the case where several <xsl:key>s
|
||||
* have the same name one object represents all <xsl:key>s with that name
|
||||
*/
|
||||
|
||||
txXSLKey::txXSLKey(ProcessorState* aPs)
|
||||
{
|
||||
mProcessorState = aPs;
|
||||
mMaps.setOwnership(Map::eOwnsItems);
|
||||
} // txXSLKey
|
||||
|
||||
txXSLKey::~txXSLKey()
|
||||
{
|
||||
ListIterator iter(&mKeys);
|
||||
while (iter.hasNext()) {
|
||||
iter.next();
|
||||
delete (Key*)iter.remove();
|
||||
}
|
||||
} // ~txXSLKey
|
||||
|
||||
/*
|
||||
* Returns a NodeSet containing all nodes within the specified document
|
||||
* that have the value keyValue. The document is indexed in case it
|
||||
* hasn't been searched previously. The returned nodeset is owned by
|
||||
* the txXSLKey object
|
||||
* @param aKeyValue Value to search for
|
||||
* @param aDoc Document to search in
|
||||
* @return a NodeSet* containing all nodes in doc matching with value
|
||||
* keyValue
|
||||
*/
|
||||
const NodeSet* txXSLKey::getNodes(String& aKeyValue, Document* aDoc)
|
||||
{
|
||||
NamedMap* map = (NamedMap*)mMaps.get(aDoc);
|
||||
if (!map) {
|
||||
map = addDocument(aDoc);
|
||||
if (!map)
|
||||
return &mEmptyNodeset;
|
||||
}
|
||||
|
||||
NodeSet* nodes = (NodeSet*)map->get(aKeyValue);
|
||||
if (!nodes)
|
||||
return &mEmptyNodeset;
|
||||
|
||||
return nodes;
|
||||
} // getNodes
|
||||
|
||||
/*
|
||||
* Adds a match/use pair. Returns MB_FALSE if matchString or useString
|
||||
* can't be parsed.
|
||||
* @param aMatchString String to be parsed as match-pattern
|
||||
* @param aUseString String to be parsed as use-expression
|
||||
* @return MB_FALSE if matchString or useString can't be parsed
|
||||
* MB_TRUE otherwise
|
||||
*/
|
||||
MBool txXSLKey::addKey(const String& aMatchString, const String& aUseString)
|
||||
{
|
||||
Key* key = new Key;
|
||||
if (!key)
|
||||
return MB_FALSE;
|
||||
|
||||
key->matchPattern = mProcessorState->getPatternExpr(aMatchString);
|
||||
key->useExpr = mProcessorState->getExpr(aUseString);
|
||||
if (!key->matchPattern || !key->useExpr) {
|
||||
delete key;
|
||||
return MB_FALSE;
|
||||
}
|
||||
mKeys.add(key);
|
||||
return MB_TRUE;
|
||||
} // addKey
|
||||
|
||||
/*
|
||||
* Indexes a document and adds it to the set of indexed documents
|
||||
* @param aDoc Document to index and add
|
||||
* @returns a NamedMap* containing the index
|
||||
*/
|
||||
NamedMap* txXSLKey::addDocument(Document* aDoc)
|
||||
{
|
||||
NamedMap* map = new NamedMap;
|
||||
if (!map)
|
||||
return NULL;
|
||||
map->setObjectDeletion(MB_TRUE);
|
||||
mMaps.put(aDoc, map);
|
||||
indexTree(aDoc, map);
|
||||
return map;
|
||||
} // addDocument
|
||||
|
||||
/*
|
||||
* Recursively searches a node, its attributes and its subtree for
|
||||
* nodes matching any of the keys match-patterns.
|
||||
* @param aNode node to search
|
||||
* @param aMap index to add search result in
|
||||
*/
|
||||
void txXSLKey::indexTree(Node* aNode, NamedMap* aMap)
|
||||
{
|
||||
testNode(aNode, aMap);
|
||||
|
||||
// check if the nodes attributes matches
|
||||
NamedNodeMap* attrs = aNode->getAttributes();
|
||||
if (attrs) {
|
||||
for (UInt32 i=0; i<attrs->getLength(); i++) {
|
||||
testNode(attrs->item(i), aMap);
|
||||
}
|
||||
}
|
||||
|
||||
Node* child = aNode->getFirstChild();
|
||||
while (child) {
|
||||
indexTree(child, aMap);
|
||||
child = child->getNextSibling();
|
||||
}
|
||||
} // indexTree
|
||||
|
||||
/*
|
||||
* Tests one node if it matches any of the keys match-patterns. If
|
||||
* the node matches its values are added to the index.
|
||||
* @param aNode node to test
|
||||
* @param aMap index to add values to
|
||||
*/
|
||||
void txXSLKey::testNode(Node* aNode, NamedMap* aMap)
|
||||
{
|
||||
String val;
|
||||
NodeSet *nodeSet;
|
||||
|
||||
ListIterator iter(&mKeys);
|
||||
while (iter.hasNext())
|
||||
{
|
||||
Key* key=(Key*)iter.next();
|
||||
if (key->matchPattern->matches(aNode, 0, mProcessorState)) {
|
||||
NodeSet contextNodeSet;
|
||||
contextNodeSet.add(aNode);
|
||||
mProcessorState->getNodeSetStack()->push(&contextNodeSet);
|
||||
mProcessorState->pushCurrentNode(aNode);
|
||||
ExprResult* exprResult = key->useExpr->evaluate(aNode, mProcessorState);
|
||||
mProcessorState->popCurrentNode();
|
||||
mProcessorState->getNodeSetStack()->pop();
|
||||
if (exprResult->getResultType() == ExprResult::NODESET) {
|
||||
NodeSet* res = (NodeSet*)exprResult;
|
||||
for (int i=0; i<res->size(); i++) {
|
||||
val.clear();
|
||||
XMLDOMUtils::getNodeValue(res->get(i), &val);
|
||||
|
||||
nodeSet = (NodeSet*)aMap->get(val);
|
||||
if (!nodeSet) {
|
||||
nodeSet = new NodeSet;
|
||||
if (!nodeSet)
|
||||
return;
|
||||
aMap->put(val, nodeSet);
|
||||
}
|
||||
nodeSet->add(aNode);
|
||||
}
|
||||
}
|
||||
else {
|
||||
exprResult->stringValue(val);
|
||||
nodeSet = (NodeSet*)aMap->get(val);
|
||||
if (!nodeSet) {
|
||||
nodeSet = new NodeSet;
|
||||
if (!nodeSet)
|
||||
return;
|
||||
aMap->put(val, nodeSet);
|
||||
}
|
||||
nodeSet->add(aNode);
|
||||
}
|
||||
delete exprResult;
|
||||
}
|
||||
}
|
||||
} // testNode
|
Загрузка…
Ссылка в новой задаче