Implementation of the xsl:apply-imports instruction.

b=94002 r=peterv sr=jst
This commit is contained in:
sicking%bigfoot.com 2002-01-15 10:37:00 +00:00
parent 614453083c
commit c2521b6587
4 changed files with 213 additions and 56 deletions

View File

@ -425,22 +425,60 @@ List* ProcessorState::getImportFrames()
}
/*
* Finds a template for the given Node. Only templates with
* a mode attribute equal to the given mode will be searched.
* 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,
Node* aContext,
const String& aMode)
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* frame;
ImportFrame* endFrame = 0;
txListIterator frameIter(&mImportFrames);
while (!matchTemplate && (frame = (ImportFrame*)frameIter.next())) {
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);
@ -448,6 +486,7 @@ Node* ProcessorState::findTemplate(Node* aNode,
if (templates) {
txListIterator templateIter(templates);
// Find template with highest priority
MatchableTemplate* templ;
while ((templ = (MatchableTemplate*)templateIter.next())) {
String priorityAttr;
@ -463,14 +502,15 @@ Node* ProcessorState::findTemplate(Node* aNode,
}
else {
tmpPriority = templ->mMatch->getDefaultPriority(aNode,
aContext,
0,
this);
}
if (tmpPriority >= currentPriority &&
templ->mMatch->matches(aNode, aContext, this)) {
templ->mMatch->matches(aNode, 0, this)) {
matchTemplate = templ->mTemplate;
*aImportFrame = frame;
currentPriority = tmpPriority;
}
}
@ -478,7 +518,23 @@ Node* ProcessorState::findTemplate(Node* aNode,
}
return matchTemplate;
} //-- findTemplate
}
/*
* 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
@ -1274,9 +1330,10 @@ void ProcessorState::initialize() {
decimalFormats.setObjectDeletion(MB_TRUE);
}
ProcessorState::ImportFrame::ImportFrame()
ProcessorState::ImportFrame::ImportFrame(ImportFrame* aFirstNotImported)
{
mNamedAttributeSets.setObjectDeletion(MB_TRUE);
mFirstNotImported = aFirstNotImported;
}
ProcessorState::ImportFrame::~ImportFrame()

View File

@ -76,7 +76,7 @@ public:
*/
class ImportFrame {
public:
ImportFrame();
ImportFrame(ImportFrame* aFirstNotImported);
~ImportFrame();
// Map of named templates
@ -92,16 +92,16 @@ public:
// Map of named attribute sets
NamedMap mNamedAttributeSets;
// ImportFrame which is the first one *not* imported by this frame
ImportFrame* mFirstNotImported;
// The following stuff is missing here:
// ImportFrame(?) for xsl:apply-imports
// Nametests for xsl:strip-space and xsl:preserve-space
// Namespace aliases (xsl:namespace-alias)
// Named attribute sets
// Toplevel variables/parameters
// Output specifier (xsl:output)
};
// To be able to do some cleaning up in destructor
friend class ImportFrame;
/*
@ -234,17 +234,52 @@ public:
**/
List* getImportFrames();
/**
* Finds a template for the given Node. Only templates without
* a mode attribute will be searched.
**/
Element* findTemplate(Node* node, Node* context);
/*
* 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* findTemplate(Node* aNode,
const String& aMode,
ImportFrame** aImportFrame);
/*
* Finds a template for the given Node. Only templates with
* a mode attribute equal to the given mode will be searched.
* 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* findTemplate(Node* aNode, Node* aContext, const String& aMode);
Node* findTemplate(Node* aNode,
const String& aMode,
ImportFrame* aImportedBy,
ImportFrame** aImportFrame);
/*
* Struct holding information about a current template rule
*/
struct TemplateRule {
ImportFrame* mFrame;
const String* mMode;
NamedMap* mParams;
};
/*
* Gets current template rule
*/
TemplateRule* getCurrentTemplateRule();
/*
* Sets current template rule
*/
void setCurrentTemplateRule(TemplateRule* aTemplateRule);
/**
* Determines if the given XSL node allows Whitespace stripping
@ -458,6 +493,11 @@ private:
*/
Map mPatternHashes[2];
/*
* Current template rule
*/
TemplateRule* mCurrentTemplateRule;
Element* mXPathParseContext;
Stack nodeSetStack;
Document* mSourceDocument;

View File

@ -106,6 +106,7 @@ XSLTProcessor::XSLTProcessor() {
//-- create XSL element types
xslTypes.setObjectDeletion(MB_TRUE);
xslTypes.put(APPLY_IMPORTS, new XSLType(XSLType::APPLY_IMPORTS));
xslTypes.put(APPLY_TEMPLATES, new XSLType(XSLType::APPLY_TEMPLATES));
xslTypes.put(ATTRIBUTE, new XSLType(XSLType::ATTRIBUTE));
xslTypes.put(ATTRIBUTE_SET, new XSLType(XSLType::ATTRIBUTE_SET));
@ -502,11 +503,22 @@ void XSLTProcessor::processTopLevel(Document* aSource,
element->getBaseURI(),
href);
importFrame->addAfter(new ProcessorState::ImportFrame);
importFrame->next();
// Create a new ImportFrame with correct firstNotImported
ProcessorState::ImportFrame *nextFrame, *newFrame;
nextFrame =
(ProcessorState::ImportFrame*)importFrame->next();
newFrame = new ProcessorState::ImportFrame(nextFrame);
if (!newFrame) {
// XXX ErrorReport: out of memory
break;
}
// Insert frame and process stylesheet
importFrame->addBefore(newFrame);
importFrame->previous();
processInclude(href, aSource, importFrame, aPs);
// Restore iterator to initial position
importFrame->previous();
break;
@ -762,14 +774,14 @@ Document* XSLTProcessor::process
//-------------------------------------------------------/
ListIterator importFrame(ps.getImportFrames());
importFrame.addAfter(new ProcessorState::ImportFrame);
importFrame.addAfter(new ProcessorState::ImportFrame(0));
importFrame.next();
processStylesheet(&xmlDocument, &xslDocument, &importFrame, &ps);
//----------------------------------------/
//- Process root of XML source document -/
//--------------------------------------/
process(&xmlDocument, &xmlDocument, NULL_STRING, &ps);
process(&xmlDocument, NULL_STRING, &ps);
//-- return result Document
return result;
@ -808,14 +820,14 @@ void XSLTProcessor::process
//-------------------------------------------------------/
ListIterator importFrame(ps.getImportFrames());
importFrame.addAfter(new ProcessorState::ImportFrame);
importFrame.addAfter(new ProcessorState::ImportFrame(0));
importFrame.next();
processStylesheet(&xmlDocument, &xslDocument, &importFrame, &ps);
//----------------------------------------/
//- Process root of XML source document -/
//--------------------------------------/
process(&xmlDocument, &xmlDocument, NULL_STRING, &ps);
process(&xmlDocument, NULL_STRING, &ps);
print(*result, ps.getOutputFormat(), out);
@ -1029,17 +1041,14 @@ void XSLTProcessor::notifyError(String& errorMessage, ErrorObserver::ErrorLevel
} //-- notifyError
void XSLTProcessor::process(Node* node,
Node* context,
const String& mode,
ProcessorState* ps) {
if (!node)
return;
Node* xslTemplate = ps->findTemplate(node, context, mode);
if (xslTemplate)
processTemplate(node, xslTemplate, ps);
else
processDefaultTemplate(node, ps, NULL_STRING);
ProcessorState::ImportFrame *frame;
Node* xslTemplate = ps->findTemplate(node, mode, &frame);
processMatchedTemplate(xslTemplate, node, 0, NULL_STRING, frame, ps);
} //-- process
void XSLTProcessor::processAction
@ -1086,6 +1095,27 @@ void XSLTProcessor::processAction
switch ( getElementType(nodeName, ps) ) {
//-- xsl:apply-imports
case XSLType::APPLY_IMPORTS :
{
ProcessorState::TemplateRule* curr;
Node* xslTemplate;
ProcessorState::ImportFrame *frame;
curr = ps->getCurrentTemplateRule();
if (!curr) {
String err("apply-imports not allowed here");
ps->recieveError(err);
break;
}
xslTemplate = ps->findTemplate(node, *curr->mMode,
curr->mFrame, &frame);
processMatchedTemplate(xslTemplate, node, curr->mParams,
*curr->mMode, frame, ps);
break;
}
//-- xsl:apply-templates
case XSLType::APPLY_TEMPLATES :
{
@ -1129,18 +1159,14 @@ void XSLTProcessor::processAction
NamedMap* actualParams = processParameters(actionElement, node, ps);
for (int i = 0; i < nodeSet->size(); i++) {
ProcessorState::ImportFrame *frame;
Node* currNode = nodeSet->get(i);
Node* xslTemplate;
xslTemplate = ps->findTemplate(currNode, node, mode);
if (xslTemplate) {
ps->pushCurrentNode(currNode);
processTemplate(currNode, xslTemplate, ps, actualParams);
ps->popCurrentNode();
}
else {
processDefaultTemplate(currNode, ps, mode);
}
xslTemplate = ps->findTemplate(currNode, mode, &frame);
processMatchedTemplate(xslTemplate, currNode,
actualParams, mode, frame, ps);
}
//-- remove nodeSet from context stack
ps->getNodeSetStack()->pop();
@ -1370,6 +1396,11 @@ void XSLTProcessor::processAction
}
sorter.sortNodeSet(nodeSet);
// Set current template to null
ProcessorState::TemplateRule *oldTemplate;
oldTemplate = ps->getCurrentTemplateRule();
ps->setCurrentTemplateRule(0);
for (int i = 0; i < nodeSet->size(); i++) {
Node* currNode = nodeSet->get(i);
ps->pushCurrentNode(currNode);
@ -1377,7 +1408,9 @@ void XSLTProcessor::processAction
ps->popCurrentNode();
}
//-- remove nodeSet from context stack
ps->setCurrentTemplateRule(oldTemplate);
// Remove nodeSet from context stack
ps->getNodeSetStack()->pop();
}
else {
@ -1766,6 +1799,32 @@ void XSLTProcessor::processTemplate(Node* node, Node* xslTemplate, ProcessorStat
bindings->pop();
} //-- processTemplate
void XSLTProcessor::processMatchedTemplate(Node* aXslTemplate,
Node* aNode,
NamedMap* aParams,
const String& aMode,
ProcessorState::ImportFrame* aFrame,
ProcessorState* aPs)
{
if (aXslTemplate) {
ProcessorState::TemplateRule *oldTemplate, newTemplate;
oldTemplate = aPs->getCurrentTemplateRule();
newTemplate.mFrame = aFrame;
newTemplate.mMode = &aMode;
newTemplate.mParams = aParams;
aPs->setCurrentTemplateRule(&newTemplate);
aPs->pushCurrentNode(aNode);
processTemplate(aNode, aXslTemplate, aPs, aParams);
aPs->popCurrentNode();
aPs->setCurrentTemplateRule(oldTemplate);
}
else {
processDefaultTemplate(aNode, aPs, aMode);
}
}
/**
* Invokes the default template for the specified node
* @param node context node
@ -1804,15 +1863,11 @@ void XSLTProcessor::processDefaultTemplate(Node* node,
ps->getNodeSetStack()->push(nodeSet);
for (int i = 0; i < nodeSet->size(); i++) {
Node* currNode = nodeSet->get(i);
Node* xslTemplate = ps->findTemplate(currNode, node, mode);
if (xslTemplate) {
ps->pushCurrentNode(currNode);
processTemplate(currNode, xslTemplate, ps, NULL);
ps->popCurrentNode();
}
else {
processDefaultTemplate(currNode, ps, mode);
}
ProcessorState::ImportFrame *frame;
Node* xslTemplate = ps->findTemplate(currNode, mode, &frame);
processMatchedTemplate(xslTemplate, currNode, 0, mode, frame,
ps);
}
//-- remove nodeSet from context stack
ps->getNodeSetStack()->pop();
@ -2094,14 +2149,14 @@ XSLTProcessor::TransformDocument(nsIDOMNode* aSourceDOM,
//- index templates and process top level xsl elements -/
//------------------------------------------------------/
ListIterator importFrame(ps->getImportFrames());
importFrame.addAfter(new ProcessorState::ImportFrame);
importFrame.addAfter(new ProcessorState::ImportFrame(0));
importFrame.next();
processStylesheet(sourceDocument, xslDocument, &importFrame, ps);
//---------------------------------------/
//- Process root of XML source document -/
//---------------------------------------/
process(sourceNode, sourceNode, NULL_STRING, ps);
process(sourceNode, NULL_STRING, ps);
// XXX Hack, ProcessorState::addToResultTree should do the right thing
// for adding several consecutive text nodes

View File

@ -313,7 +313,6 @@ private:
#endif
void process(Node* node,
Node* context,
const String& mode,
ProcessorState* ps);
@ -336,6 +335,12 @@ private:
void processTemplate(Node* node, Node* xslTemplate, ProcessorState* ps, NamedMap* actualParams = NULL);
void processTemplateParams(Node* xslTemplate, Node* context, ProcessorState* ps, NamedMap* actualParams);
void processMatchedTemplate(Node* aXslTemplate,
Node* aNode,
NamedMap* aParams,
const String& aMode,
ProcessorState::ImportFrame* aFrame,
ProcessorState* aPs);
/**
* Invokes the default template for the specified node
* @param node context node