Back to index

lightning-sunbird  0.9+nobinonly
txStylesheet.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is TransforMiiX XSLT processor code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Jonas Sicking.
00019  * Portions created by the Initial Developer are Copyright (C) 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Jonas Sicking <jonas@sicking.cc>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "txStylesheet.h"
00040 #include "Expr.h"
00041 #include "txXSLTPatterns.h"
00042 #include "txToplevelItems.h"
00043 #include "txInstructions.h"
00044 #include "XSLTFunctions.h"
00045 #include "TxLog.h"
00046 #include "txKey.h"
00047 
00048 txStylesheet::txStylesheet()
00049     : mRootFrame(nsnull),
00050       mNamedTemplates(PR_FALSE),
00051       mDecimalFormats(PR_TRUE),
00052       mAttributeSets(PR_FALSE),
00053       mGlobalVariables(PR_TRUE),
00054       mKeys(PR_TRUE)
00055 {
00056 }
00057 
00058 nsresult
00059 txStylesheet::init()
00060 {
00061     mRootFrame = new ImportFrame;
00062     NS_ENSURE_TRUE(mRootFrame, NS_ERROR_OUT_OF_MEMORY);
00063     
00064     // Create default templates
00065     // element/root template
00066     mContainerTemplate = new txPushParams;
00067     NS_ENSURE_TRUE(mContainerTemplate, NS_ERROR_OUT_OF_MEMORY);
00068 
00069     nsAutoPtr<txNodeTest> nt(new txNodeTypeTest(txNodeTypeTest::NODE_TYPE));
00070     NS_ENSURE_TRUE(nt, NS_ERROR_OUT_OF_MEMORY);
00071 
00072     nsAutoPtr<Expr> nodeExpr(new LocationStep(nt, LocationStep::CHILD_AXIS));
00073     NS_ENSURE_TRUE(nodeExpr, NS_ERROR_OUT_OF_MEMORY);
00074 
00075     txPushNewContext* pushContext = new txPushNewContext(nodeExpr);
00076     mContainerTemplate->mNext = pushContext;
00077     NS_ENSURE_TRUE(pushContext, NS_ERROR_OUT_OF_MEMORY);
00078 
00079     txApplyDefaultElementTemplate* applyTemplates =
00080         new txApplyDefaultElementTemplate;
00081     pushContext->mNext = applyTemplates;
00082     NS_ENSURE_TRUE(applyTemplates, NS_ERROR_OUT_OF_MEMORY);
00083 
00084     txLoopNodeSet* loopNodeSet = new txLoopNodeSet(applyTemplates);
00085     applyTemplates->mNext = loopNodeSet;
00086     NS_ENSURE_TRUE(loopNodeSet, NS_ERROR_OUT_OF_MEMORY);
00087 
00088     txPopParams* popParams = new txPopParams;
00089     pushContext->mBailTarget = loopNodeSet->mNext = popParams;
00090     NS_ENSURE_TRUE(popParams, NS_ERROR_OUT_OF_MEMORY);
00091 
00092     popParams->mNext = new txReturn();
00093     NS_ENSURE_TRUE(popParams->mNext, NS_ERROR_OUT_OF_MEMORY);
00094 
00095     // attribute/textnode template
00096     nt = new txNodeTypeTest(txNodeTypeTest::NODE_TYPE);
00097     NS_ENSURE_TRUE(nt, NS_ERROR_OUT_OF_MEMORY);
00098 
00099     nodeExpr = new LocationStep(nt, LocationStep::SELF_AXIS);
00100     NS_ENSURE_TRUE(nodeExpr, NS_ERROR_OUT_OF_MEMORY);
00101 
00102     mCharactersTemplate = new txValueOf(nodeExpr, PR_FALSE);
00103     NS_ENSURE_TRUE(mCharactersTemplate, NS_ERROR_OUT_OF_MEMORY);
00104 
00105     mCharactersTemplate->mNext = new txReturn();
00106     NS_ENSURE_TRUE(mCharactersTemplate->mNext, NS_ERROR_OUT_OF_MEMORY);
00107 
00108     // pi/comment/namespace template
00109     mEmptyTemplate = new txReturn();
00110     NS_ENSURE_TRUE(mEmptyTemplate, NS_ERROR_OUT_OF_MEMORY);
00111 
00112     return NS_OK;
00113 }
00114 
00115 txStylesheet::~txStylesheet()
00116 {
00117     // Delete all ImportFrames
00118     delete mRootFrame;
00119     txListIterator frameIter(&mImportFrames);
00120     while (frameIter.hasNext()) {
00121         delete NS_STATIC_CAST(ImportFrame*, frameIter.next());
00122     }
00123 
00124     txListIterator instrIter(&mTemplateInstructions);
00125     while (instrIter.hasNext()) {
00126         delete NS_STATIC_CAST(txInstruction*, instrIter.next());
00127     }
00128     
00129     // We can't make the map own its values because then we wouldn't be able
00130     // to merge attributesets of the same name
00131     txExpandedNameMap::iterator attrSetIter(mAttributeSets);
00132     while (attrSetIter.next()) {
00133         delete attrSetIter.value();
00134     }
00135 }
00136 
00137 txInstruction*
00138 txStylesheet::findTemplate(const txXPathNode& aNode,
00139                            const txExpandedName& aMode,
00140                            txIMatchContext* aContext,
00141                            ImportFrame* aImportedBy,
00142                            ImportFrame** aImportFrame)
00143 {
00144     NS_ASSERTION(aImportFrame, "missing ImportFrame pointer");
00145 
00146     *aImportFrame = nsnull;
00147     txInstruction* matchTemplate = nsnull;
00148     ImportFrame* endFrame = nsnull;
00149     txListIterator frameIter(&mImportFrames);
00150 
00151     if (aImportedBy) {
00152         ImportFrame* curr = NS_STATIC_CAST(ImportFrame*, frameIter.next());
00153         while (curr != aImportedBy) {
00154                curr = NS_STATIC_CAST(ImportFrame*, frameIter.next());
00155         }
00156         endFrame = aImportedBy->mFirstNotImported;
00157     }
00158 
00159 #ifdef PR_LOGGING
00160     txPattern* match = 0;
00161 #endif
00162 
00163     ImportFrame* frame;
00164     while (!matchTemplate &&
00165            (frame = NS_STATIC_CAST(ImportFrame*, frameIter.next())) &&
00166            frame != endFrame) {
00167 
00168         // get templatelist for this mode
00169         txList* templates =
00170             NS_STATIC_CAST(txList*, frame->mMatchableTemplates.get(aMode));
00171 
00172         if (templates) {
00173             txListIterator templateIter(templates);
00174 
00175             // Find template with highest priority
00176             MatchableTemplate* templ;
00177             while (!matchTemplate &&
00178                    (templ =
00179                     NS_STATIC_CAST(MatchableTemplate*, templateIter.next()))) {
00180                 if (templ->mMatch->matches(aNode, aContext)) {
00181                     matchTemplate = templ->mFirstInstruction;
00182                     *aImportFrame = frame;
00183 #ifdef PR_LOGGING
00184                     match = templ->mMatch;
00185 #endif
00186                 }
00187             }
00188         }
00189     }
00190 
00191 #ifdef PR_LOGGING
00192     nsAutoString mode, nodeName;
00193     if (aMode.mLocalName) {
00194         aMode.mLocalName->ToString(mode);
00195     }
00196     txXPathNodeUtils::getNodeName(aNode, nodeName);
00197     if (matchTemplate) {
00198         nsAutoString matchAttr;
00199 #ifdef TX_TO_STRING
00200         match->toString(matchAttr);
00201 #endif
00202         PR_LOG(txLog::xslt, PR_LOG_DEBUG,
00203                ("MatchTemplate, Pattern %s, Mode %s, Node %s\n",
00204                 NS_LossyConvertUCS2toASCII(matchAttr).get(),
00205                 NS_LossyConvertUCS2toASCII(mode).get(),
00206                 NS_LossyConvertUCS2toASCII(nodeName).get()));
00207     }
00208     else {
00209         PR_LOG(txLog::xslt, PR_LOG_DEBUG,
00210                ("No match, Node %s, Mode %s\n", 
00211                 NS_LossyConvertUCS2toASCII(nodeName).get(),
00212                 NS_LossyConvertUCS2toASCII(mode).get()));
00213     }
00214 #endif
00215 
00216     if (!matchTemplate) {
00217         if (txXPathNodeUtils::isElement(aNode) ||
00218             txXPathNodeUtils::isRoot(aNode)) {
00219             matchTemplate = mContainerTemplate;
00220         }
00221         else if (txXPathNodeUtils::isAttribute(aNode) ||
00222                  txXPathNodeUtils::isText(aNode)) {
00223             matchTemplate = mCharactersTemplate;
00224         }
00225         else {
00226             matchTemplate = mEmptyTemplate;
00227         }
00228     }
00229 
00230     return matchTemplate;
00231 }
00232 
00233 txDecimalFormat*
00234 txStylesheet::getDecimalFormat(const txExpandedName& aName)
00235 {
00236     return NS_STATIC_CAST(txDecimalFormat*, mDecimalFormats.get(aName));
00237 }
00238 
00239 txInstruction*
00240 txStylesheet::getAttributeSet(const txExpandedName& aName)
00241 {
00242     return NS_STATIC_CAST(txInstruction*, mAttributeSets.get(aName));
00243 }
00244 
00245 txInstruction*
00246 txStylesheet::getNamedTemplate(const txExpandedName& aName)
00247 {
00248     return NS_STATIC_CAST(txInstruction*, mNamedTemplates.get(aName));
00249 }
00250 
00251 txOutputFormat*
00252 txStylesheet::getOutputFormat()
00253 {
00254     return &mOutputFormat;
00255 }
00256 
00257 txStylesheet::GlobalVariable*
00258 txStylesheet::getGlobalVariable(const txExpandedName& aName)
00259 {
00260     return NS_STATIC_CAST(GlobalVariable*, mGlobalVariables.get(aName));
00261 }
00262 
00263 const txExpandedNameMap&
00264 txStylesheet::getKeyMap()
00265 {
00266     return mKeys;
00267 }
00268 
00269 PRBool
00270 txStylesheet::isStripSpaceAllowed(const txXPathNode& aNode, txIMatchContext* aContext)
00271 {
00272     PRInt32 frameCount = mStripSpaceTests.Count();
00273     if (frameCount == 0) {
00274         return PR_FALSE;
00275     }
00276 
00277     txXPathTreeWalker walker(aNode);
00278 
00279     if (txXPathNodeUtils::isText(walker.getCurrentPosition()) &&
00280         (!txXPathNodeUtils::isWhitespace(aNode) || !walker.moveToParent())) {
00281         return PR_FALSE;
00282     }
00283 
00284     const txXPathNode& node = walker.getCurrentPosition();
00285 
00286     if (!txXPathNodeUtils::isElement(node)) {
00287         return PR_FALSE;
00288     }
00289 
00290     // check Whitespace stipping handling list against given Node
00291     PRInt32 i;
00292     for (i = 0; i < frameCount; ++i) {
00293         txStripSpaceTest* sst =
00294             NS_STATIC_CAST(txStripSpaceTest*, mStripSpaceTests[i]);
00295         if (sst->matches(node, aContext)) {
00296             return sst->stripsSpace() && !XMLUtils::getXMLSpacePreserve(node);
00297         }
00298     }
00299 
00300     return PR_FALSE;
00301 }
00302 
00303 nsresult
00304 txStylesheet::doneCompiling()
00305 {
00306     nsresult rv = NS_OK;
00307     // Collect all importframes into a single ordered list
00308     txListIterator frameIter(&mImportFrames);
00309     rv = frameIter.addAfter(mRootFrame);
00310     NS_ENSURE_SUCCESS(rv, rv);
00311     
00312     mRootFrame = nsnull;
00313     frameIter.next();
00314     rv = addFrames(frameIter);
00315     NS_ENSURE_SUCCESS(rv, rv);
00316 
00317     // Loop through importframes in decreasing-precedence-order and process
00318     // all items
00319     frameIter.reset();
00320     ImportFrame* frame;
00321     while ((frame = NS_STATIC_CAST(ImportFrame*, frameIter.next()))) {
00322         nsVoidArray frameStripSpaceTests;
00323 
00324         txListIterator itemIter(&frame->mToplevelItems);
00325         itemIter.resetToEnd();
00326         txToplevelItem* item;
00327         while ((item = NS_STATIC_CAST(txToplevelItem*, itemIter.previous()))) {
00328             switch (item->getType()) {
00329                 case txToplevelItem::attributeSet:
00330                 {
00331                     rv = addAttributeSet(NS_STATIC_CAST(txAttributeSetItem*,
00332                                                         item));
00333                     NS_ENSURE_SUCCESS(rv, rv);
00334                     break;
00335                 }
00336                 case txToplevelItem::dummy:
00337                 case txToplevelItem::import:
00338                 {
00339                     break;
00340                 }
00341                 case txToplevelItem::output:
00342                 {
00343                     mOutputFormat.merge(NS_STATIC_CAST(txOutputItem*, item)->mFormat);
00344                     break;
00345                 }
00346                 case txToplevelItem::stripSpace:
00347                 {
00348                     rv = addStripSpace(NS_STATIC_CAST(txStripSpaceItem*, item),
00349                                        frameStripSpaceTests);
00350                     NS_ENSURE_SUCCESS(rv, rv);
00351                     break;
00352                 }
00353                 case txToplevelItem::templ:
00354                 {
00355                     rv = addTemplate(NS_STATIC_CAST(txTemplateItem*, item),
00356                                      frame);
00357                     NS_ENSURE_SUCCESS(rv, rv);
00358 
00359                     break;
00360                 }
00361                 case txToplevelItem::variable:
00362                 {
00363                     rv = addGlobalVariable(NS_STATIC_CAST(txVariableItem*,
00364                                                           item));
00365                     NS_ENSURE_SUCCESS(rv, rv);
00366 
00367                     break;
00368                 }
00369             }
00370             delete item;
00371             itemIter.remove(); //remove() moves to the previous
00372             itemIter.next();
00373         }
00374         if (!mStripSpaceTests.AppendElements(frameStripSpaceTests)) {
00375             return NS_ERROR_OUT_OF_MEMORY;
00376         }
00377         
00378         frameStripSpaceTests.Clear();
00379     }
00380 
00381     if (!mDecimalFormats.get(txExpandedName())) {
00382         nsAutoPtr<txDecimalFormat> format(new txDecimalFormat);
00383         NS_ENSURE_TRUE(format, NS_ERROR_OUT_OF_MEMORY);
00384         
00385         rv = mDecimalFormats.add(txExpandedName(), format);
00386         NS_ENSURE_SUCCESS(rv, rv);
00387         
00388         format.forget();
00389     }
00390 
00391     return NS_OK;
00392 }
00393 
00394 nsresult
00395 txStylesheet::addTemplate(txTemplateItem* aTemplate,
00396                           ImportFrame* aImportFrame)
00397 {
00398     NS_ASSERTION(aTemplate, "missing template");
00399 
00400     txInstruction* instr = aTemplate->mFirstInstruction;
00401     nsresult rv = mTemplateInstructions.add(instr);
00402     NS_ENSURE_SUCCESS(rv, rv);
00403 
00404     // mTemplateInstructions now owns the instructions
00405     aTemplate->mFirstInstruction.forget();
00406 
00407     if (!aTemplate->mName.isNull()) {
00408         rv = mNamedTemplates.add(aTemplate->mName, instr);
00409         NS_ENSURE_TRUE(NS_SUCCEEDED(rv) || rv == NS_ERROR_XSLT_ALREADY_SET,
00410                        rv);
00411     }
00412 
00413     if (!aTemplate->mMatch) {
00414         // This is no error, see section 6 Named Templates
00415 
00416         return NS_OK;
00417     }
00418 
00419     // get the txList for the right mode
00420     txList* templates =
00421         NS_STATIC_CAST(txList*,
00422                        aImportFrame->mMatchableTemplates.get(aTemplate->mMode));
00423 
00424     if (!templates) {
00425         nsAutoPtr<txList> newList(new txList);
00426         NS_ENSURE_TRUE(newList, NS_ERROR_OUT_OF_MEMORY);
00427 
00428         rv = aImportFrame->mMatchableTemplates.add(aTemplate->mMode, newList);
00429         NS_ENSURE_SUCCESS(rv, rv);
00430         
00431         templates = newList.forget();
00432     }
00433 
00434     // Add the simple patterns to the list of matchable templates, according
00435     // to default priority
00436     txList simpleMatches;
00437     rv = aTemplate->mMatch->getSimplePatterns(simpleMatches);
00438     if (simpleMatches.get(0) == aTemplate->mMatch) {
00439         aTemplate->mMatch.forget();
00440     }
00441     
00442     txListIterator simples(&simpleMatches);
00443     while (simples.hasNext()) {
00444         // XXX if we fail in this loop, we leak the remaining simple patterns
00445         nsAutoPtr<txPattern> simple(NS_STATIC_CAST(txPattern*, simples.next()));
00446         double priority = aTemplate->mPrio;
00447         if (Double::isNaN(priority)) {
00448             priority = simple->getDefaultPriority();
00449             NS_ASSERTION(!Double::isNaN(priority),
00450                          "simple pattern without default priority");
00451         }
00452         nsAutoPtr<MatchableTemplate>
00453             nt(new MatchableTemplate(instr, simple, priority));
00454         NS_ENSURE_TRUE(nt, NS_ERROR_OUT_OF_MEMORY);
00455 
00456         txListIterator templ(templates);
00457         while (templ.hasNext()) {
00458             MatchableTemplate* mt = NS_STATIC_CAST(MatchableTemplate*,
00459                                                    templ.next());
00460             if (priority > mt->mPriority) {
00461                 rv = templ.addBefore(nt);
00462                 NS_ENSURE_SUCCESS(rv, rv);
00463 
00464                 nt.forget();
00465                 break;
00466             }
00467         }
00468         if (nt) {
00469             rv = templates->add(nt);
00470             NS_ENSURE_SUCCESS(rv, rv);
00471 
00472             nt.forget();
00473         }
00474     }
00475 
00476     return NS_OK;
00477 }
00478 
00479 nsresult
00480 txStylesheet::addFrames(txListIterator& aInsertIter)
00481 {
00482     ImportFrame* frame = NS_STATIC_CAST(ImportFrame*, aInsertIter.current());
00483     nsresult rv = NS_OK;
00484     txListIterator iter(&frame->mToplevelItems);
00485     txToplevelItem* item;
00486     while ((item = NS_STATIC_CAST(txToplevelItem*, iter.next()))) {
00487         if (item->getType() == txToplevelItem::import) {
00488             txImportItem* import = NS_STATIC_CAST(txImportItem*, item);
00489             import->mFrame->mFirstNotImported =
00490                 NS_STATIC_CAST(ImportFrame*, aInsertIter.next());
00491             rv = aInsertIter.addBefore(import->mFrame);
00492             NS_ENSURE_SUCCESS(rv, rv);
00493 
00494             import->mFrame.forget();
00495             aInsertIter.previous();
00496             rv = addFrames(aInsertIter);
00497             NS_ENSURE_SUCCESS(rv, rv);
00498             aInsertIter.previous();
00499         }
00500     }
00501     
00502     return NS_OK;
00503 }
00504 
00505 nsresult
00506 txStylesheet::addStripSpace(txStripSpaceItem* aStripSpaceItem,
00507                             nsVoidArray& frameStripSpaceTests)
00508 {
00509     PRInt32 testCount = aStripSpaceItem->mStripSpaceTests.Count();
00510     for (; testCount > 0; --testCount) {
00511         txStripSpaceTest* sst =
00512             NS_STATIC_CAST(txStripSpaceTest*,
00513                            aStripSpaceItem->mStripSpaceTests[testCount-1]);
00514         double priority = sst->getDefaultPriority();
00515         PRInt32 i, frameCount = frameStripSpaceTests.Count();
00516         for (i = 0; i < frameCount; ++i) {
00517             txStripSpaceTest* fsst =
00518                 NS_STATIC_CAST(txStripSpaceTest*, frameStripSpaceTests[i]);
00519             if (fsst->getDefaultPriority() < priority) {
00520                 break;
00521             }
00522         }
00523         if (!frameStripSpaceTests.InsertElementAt(sst, i)) {
00524             return NS_ERROR_OUT_OF_MEMORY;
00525         }
00526 
00527         aStripSpaceItem->mStripSpaceTests.RemoveElementAt(testCount-1);
00528     }
00529 
00530     return NS_OK;
00531 }
00532 
00533 nsresult
00534 txStylesheet::addAttributeSet(txAttributeSetItem* aAttributeSetItem)
00535 {
00536     nsresult rv = NS_OK;
00537     txInstruction* oldInstr =
00538         NS_STATIC_CAST(txInstruction*,
00539                        mAttributeSets.get(aAttributeSetItem->mName));
00540     if (!oldInstr) {
00541         rv = mAttributeSets.add(aAttributeSetItem->mName,
00542                                 aAttributeSetItem->mFirstInstruction);
00543         NS_ENSURE_SUCCESS(rv, rv);
00544         
00545         aAttributeSetItem->mFirstInstruction.forget();
00546         
00547         return NS_OK;
00548     }
00549     
00550     // We need to prepend the new instructions before the existing ones.
00551     txInstruction* instr = aAttributeSetItem->mFirstInstruction;
00552     txInstruction* lastNonReturn = nsnull;
00553     while (instr->mNext) {
00554         lastNonReturn = instr;
00555         instr = instr->mNext;
00556     }
00557     
00558     if (!lastNonReturn) {
00559         // The new attributeset is empty, so lets just ignore it.
00560         return NS_OK;
00561     }
00562 
00563     rv = mAttributeSets.set(aAttributeSetItem->mName,
00564                             aAttributeSetItem->mFirstInstruction);
00565     NS_ENSURE_SUCCESS(rv, rv);
00566 
00567     aAttributeSetItem->mFirstInstruction.forget();
00568 
00569     delete lastNonReturn->mNext;      // Delete the txReturn...
00570     lastNonReturn->mNext = oldInstr;  // ...and link up the old instructions.
00571 
00572     return NS_OK;
00573 }
00574 
00575 nsresult
00576 txStylesheet::addGlobalVariable(txVariableItem* aVariable)
00577 {
00578     if (mGlobalVariables.get(aVariable->mName)) {
00579         return NS_OK;
00580     }
00581     nsAutoPtr<GlobalVariable> var(
00582         new GlobalVariable(aVariable->mValue, aVariable->mFirstInstruction,
00583                            aVariable->mIsParam));
00584     NS_ENSURE_TRUE(var, NS_ERROR_OUT_OF_MEMORY);
00585     
00586     nsresult rv = mGlobalVariables.add(aVariable->mName, var);
00587     NS_ENSURE_SUCCESS(rv, rv);
00588     
00589     var.forget();
00590     
00591     return NS_OK;
00592     
00593 }
00594 
00595 nsresult
00596 txStylesheet::addKey(const txExpandedName& aName,
00597                      nsAutoPtr<txPattern> aMatch, nsAutoPtr<Expr> aUse)
00598 {
00599     nsresult rv = NS_OK;
00600 
00601     txXSLKey* xslKey = NS_STATIC_CAST(txXSLKey*, mKeys.get(aName));
00602     if (!xslKey) {
00603         xslKey = new txXSLKey(aName);
00604         NS_ENSURE_TRUE(xslKey, NS_ERROR_OUT_OF_MEMORY);
00605 
00606         rv = mKeys.add(aName, xslKey);
00607         if (NS_FAILED(rv)) {
00608             delete xslKey;
00609             return rv;
00610         }
00611     }
00612     if (!xslKey->addKey(aMatch, aUse)) {
00613         return NS_ERROR_OUT_OF_MEMORY;
00614     }
00615     return NS_OK;
00616 }
00617 
00618 nsresult
00619 txStylesheet::addDecimalFormat(const txExpandedName& aName,
00620                                nsAutoPtr<txDecimalFormat> aFormat)
00621 {
00622     txDecimalFormat* existing =
00623         NS_STATIC_CAST(txDecimalFormat*, mDecimalFormats.get(aName));
00624     if (existing) {
00625         NS_ENSURE_TRUE(existing->isEqual(aFormat),
00626                        NS_ERROR_XSLT_PARSE_FAILURE);
00627 
00628         return NS_OK;
00629     }
00630 
00631     nsresult rv = mDecimalFormats.add(aName, aFormat);
00632     NS_ENSURE_SUCCESS(rv, rv);
00633     
00634     aFormat.forget();
00635 
00636     return NS_OK;
00637 }
00638 
00639 txStylesheet::ImportFrame::ImportFrame()
00640     : mMatchableTemplates(MB_TRUE),
00641       mFirstNotImported(nsnull)
00642 {
00643 }
00644 
00645 txStylesheet::ImportFrame::~ImportFrame()
00646 {
00647     // Delete templates in mMatchableTemplates
00648     txExpandedNameMap::iterator mapIter(mMatchableTemplates);
00649     while (mapIter.next()) {
00650         txListIterator templIter(NS_STATIC_CAST(txList*, mapIter.value()));
00651         MatchableTemplate* templ;
00652         while ((templ = NS_STATIC_CAST(MatchableTemplate*, templIter.next()))) {
00653             delete templ;
00654         }
00655     }
00656     
00657     txListIterator tlIter(&mToplevelItems);
00658     while (tlIter.hasNext()) {
00659         delete NS_STATIC_CAST(txToplevelItem*, tlIter.next());
00660     }
00661 }
00662 
00663 txStylesheet::GlobalVariable::GlobalVariable(nsAutoPtr<Expr> aExpr,
00664                                              nsAutoPtr<txInstruction> aFirstInstruction,
00665                                              PRBool aIsParam)
00666     : mExpr(aExpr), mFirstInstruction(aFirstInstruction), mIsParam(aIsParam)
00667 {
00668 }