2 * The contents of this file are subject to the Mozilla Public
3 * License Version 1.1 (the "License"); you may not use this file
4 * except in compliance with the License. You may obtain a copy of
5 * the License at http://www.mozilla.org/MPL/
7 * Software distributed under the License is distributed on an "AS
8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9 * implied. See the License for the specific language governing
10 * rights and limitations under the License.
12 * The Original Code is the Sablotron XSLT Processor.
14 * The Initial Developer of the Original Code is Ginger Alliance Ltd.
15 * Portions created by Ginger Alliance are Copyright (C) 2000-2002
16 * Ginger Alliance Ltd. All Rights Reserved.
20 * Alternatively, the contents of this file may be used under the
21 * terms of the GNU General Public License Version 2 or later (the
22 * "GPL"), in which case the provisions of the GPL are applicable
23 * instead of those above. If you wish to allow use of your
24 * version of this file only under the terms of the GPL and not to
25 * allow others to use your version of this file under the MPL,
26 * indicate your decision by deleting the provisions above and
27 * replace them with the notice and other provisions required by
28 * the GPL. If you do not delete the provisions above, a recipient
29 * may use your version of this file under either the MPL or the
39 // #include "xmlparse.h" - moved to parser.h
43 #include "domprovider.h"
49 #ifdef SABLOT_DEBUGGER
55 /*****************************************************************
56 R u l e I t e m methods
57 *****************************************************************/
59 RuleItem::RuleItem(XSLElement *arule,double aprio, QName &_name,
62 rule(arule), priority(aprio), name(_name), mode(_mode)
64 match = rule -> atts.find(XSLA_MATCH);
70 // has to dispose of the mode
78 /*****************************************************************
79 R u l e S L i s t methods
80 *****************************************************************/
82 RuleSList::RuleSList()
84 SList<RuleItem*>(LIST_SIZE_LARGE)
87 RuleSList::~RuleSList()
92 int RuleSList::compare(int first, int second, void *data)
94 return fcomp((*this)[first] -> priority, (*this)[second] -> priority);
98 XSLElement* RuleSList::findByName(const Tree& t, const QName &what) const
100 int theNumber = number();
101 for (int i=0; i < theNumber; i++)
102 if (t.cmpQNames((*this)[i] -> name, what))
103 return (*this)[i] -> rule;
107 /*****************************************************************
111 *****************************************************************/
113 DataLineItem::DataLineItem(Sit S_)
118 DataLineItem::~DataLineItem()
120 // the following close should be checked for error!!
121 if (_dataline && _dataline -> mode != DLMODE_CLOSED)
122 _dataline -> close(situation);
128 /************************************************************
132 ************************************************************/
134 eFlag OutputDocumentList::finish(Sit S)
136 for (int i = 0; i < number(); i++)
137 E( (*this)[i] -> finish(S) );
141 /*****************************************************************
145 *****************************************************************/
147 int DataLinesList::findNum(Str &absoluteURI, Bool _isXSL,
150 int theNumber = number();
151 for (int i = 0; i < theNumber; i++)
153 DataLineItem* item = (*this)[i];
154 if ((item->_dataline -> fullUri == absoluteURI) &&
155 (item->_isXSL == _isXSL) &&
156 (item-> _dataline -> mode == _mode ||
157 item-> _dataline -> mode == DLMODE_CLOSED))
163 Tree* DataLinesList::getTree(Str &absoluteURI, Bool _isXSL,
167 if ((n = findNum(absoluteURI, _isXSL, _mode)) != -1)
168 return (*this)[n] -> _tree;
173 eFlag DataLinesList::addLine(Sit S, DataLine *d, Tree *t, Bool isXSL,
174 Bool preparsedTree /* = FALSE */)
176 DataLineItem *item = new DataLineItem(S);
177 item -> _dataline = d;
179 item -> _isXSL = isXSL;
180 item -> _preparsedTree = preparsedTree;
185 /*****************************************************************
187 * P r o c e s s o r methods *
189 *****************************************************************/
191 // disable the MSVC warning "'this' used in the initializer list"
194 #pragma warning( disable : 4355 )
197 Processor::Processor()
199 theArena(PROC_ARENA_SIZE)
205 #pragma warning( default : 4355 )
210 theSchemeHandler = NULL;
211 theMessageHandler = NULL;
212 theSAXHandler = NULL;
213 theMiscHandler = NULL;
214 theEncHandler = NULL;
215 theSchemeUserData = theMessageUserData =
216 theSAXUserData = theMiscUserData = theEncUserData = NULL;
218 instanceSituation = NULL;
221 input = styleSheet = NULL;
224 hasMasterSituation = FALSE;
225 runsOnExternal = FALSE;
228 void Processor::prepareForRun()
230 // do this in open():
231 // vars = new VarsList();
232 input = styleSheet = NULL;
233 decimals().initialize();
236 void Processor::freeNonArgDatalines()
239 while(i < datalines.number())
241 if (datalines[i] -> _dataline -> scheme != URI_ARG)
243 datalines.freerm(i, FALSE);
247 // removing the tree here because the arena gets disposed
248 // in cleanupAfterRun(). So only the arg buffers remain.
249 // only remove the tree if not preparsed
250 if (!datalines[i] -> _preparsedTree)
251 cdelete(datalines[i] -> _tree);
252 // don't move the following line out of the else!
259 void Processor::cleanupAfterRun(Situation *Sp)
262 These deletes are now subsumed in "datalines.freeall()":
268 styleSheet = input = NULL;
271 decimals().freeall(FALSE);
273 jscontexts.freeall(FALSE);
276 outputDocuments.freeall(FALSE);
278 freeNonArgDatalines();
279 if (Sp && !Sp -> isError())
281 assert(modes.isEmpty());
282 assert(outputters_.isEmpty());
286 modes.freeall(FALSE);
287 outputters_.freeall(FALSE);
292 //DETACH: move to Tree
293 // dictionary.destroy();
295 runsOnExternal = FALSE;
298 Processor::~Processor()
301 baseURIMappings.freeall(FALSE);
302 // FIXME: MUST clear theRecoder but got no situation
303 // theRecoder.clear();
306 eFlag Processor::open(Sit S, const char *sheetURI, const char *inputURI)
312 theBase = findBaseURI(S, Str("file://") + theBase);
314 E( readTreeFromURI(S, styleSheet, temp = sheetURI, theBase, TRUE) );
315 //styleSheet -> speakDebug();
317 #ifdef SABLOT_DEBUGGER
318 if (debugger) debugger -> setBreakpoints(S, styleSheet);
321 runsOnExternal = !inputURI;
323 E( readTreeFromURI(S, input, temp = inputURI, theBase, FALSE) );
324 vars = new VarsList (*styleSheet);
329 eFlag Processor::run(Sit S, const char* resultURI, NodeHandle doc /*= NULL */)
334 theBase = findBaseURI(S, Str("file://") + theBase);
336 //strip spaces from the document
337 if (input) E( stripTree(S, *input) )
339 Log1(S, L1_EXECUTING, styleSheet -> getURI());
340 double time_was = getMillisecs();
341 E( pushOutputterForURI(S, temp = resultURI, theBase) );
342 E( outputter() -> eventBeginOutput(S) );
344 inputRoot = !nhNull(doc) ? doc : (NodeHandle)&(NZ(input) -> getRoot());
345 GP( Context ) c = new Context(inputRoot);
349 in vars, global prebindings go to call level 0,
350 global bindings to call level 1
353 // start by resolving all globals
354 //E( resolveGlobals(S, c) ); It has been done twice (XSLElement::execute)
355 E( styleSheet -> getRoot().execute(S, c, FALSE) );
359 E( outputter() -> eventTrailingNewline(S) );
360 E( outputter() -> eventEndOutput(S) );
362 //done all outputetrs
363 E( outputDocuments.finish(S) );
365 // report info about the output document to the MiscHandler
367 OutputDefinition *outDef = &(styleSheet -> outputDef);
368 MiscHandler *miscHlr = getMiscHandler(&miscUserData);
370 miscHlr -> documentInfo(
373 outDef -> getValueStr(XSLA_MEDIA_TYPE),
374 outDef -> getValueStr(XSLA_ENCODING));
376 E( popOutputter(S) );
379 //this is not needed,
380 //cleanupAfterRun takes care in the case of error
381 //assert(!outputters_.number());
383 Log1(S, L1_EXECUTION_DONE, getMillisecsDiff(time_was));
389 /*================================================================
391 finds the current binding for the variable with the given name.
392 The binding is an expression. If none is present, returns NULL.
393 ================================================================*/
395 Expression* Processor::getVarBinding(QName &which)
397 return vars -> getBinding(which);
400 /*================================================================
402 both flavours DEALLOCATE the context and set the pointer to NULL
403 ================================================================*/
405 eFlag Processor::execute(Sit S, Vertex *IP, Context *&c, Bool resolvingGlobals)
407 while (!c -> isFinished())
409 c -> setCurrentNode(c -> current());
412 E( IP -> execute(S, c, resolvingGlobals) );
416 E( execApplyTemplates(S, c, resolvingGlobals) );
424 eFlag Processor::execute(Sit S, VertexList &IPlist, Context *&c, Bool resolvingGlobals)
426 // we may need to remove some variable bindings on each pass
427 // through a for loop
428 Vertex *theParent = IPlist.number()? IPlist[0] -> parent : NULL;
429 XSLElement *theForParent;
430 if (theParent && isXSLElement(theParent) && toX(theParent) -> op == XSL_FOR_EACH)
431 theForParent = toX(theParent);
435 while (c -> current())
437 c -> setCurrentNode(c -> current());
438 E( IPlist.execute(S, c, resolvingGlobals) );
441 theForParent -> removeBindings(S);
447 eFlag Processor::execApplyTemplates(Sit S, Context *c, Bool resolvingGlobals)
450 E( NZ(styleSheet) -> findBestRule(S, rule, c, getCurrentMode(), FALSE) );
452 E( builtinRule(S, c, resolvingGlobals) )
454 E( rule -> execute(S, c, resolvingGlobals) );
458 eFlag Processor::execApplyImports(Sit S, Context *c, SubtreeInfo *subtree,
459 Bool resolvingGlobals)
463 findBestRule(S, rule, c, getCurrentMode(), TRUE, subtree) );
465 E( rule -> execute(S, c, FALSE) );
469 eFlag Processor::builtinRule(Sit S, Context *c, Bool resolvingGlobals)
471 // may assume v to be a physical vertex
472 //Vertex *v = toPhysical(c -> current());
473 NodeHandle v = c -> current();
475 switch (S.dom().getNodeType(v)) {
480 GP( Expression ) e = new Expression(styleSheet->getRoot(), EXF_LOCPATH);
481 (*e).setLS(AXIS_CHILD, EXNODE_NODE);
484 E( (*e).createContext(S, newc) );
486 E( execute(S, NULL, newc, resolvingGlobals) );
487 newc.keep(); // GP: it's NULL by this time anyway
492 //copy contents to output
494 const char *val = S.dom().getNodeValue(v);
495 E( outputter() -> eventData(S, Str(val)) );
496 S.dom().freeValue(v, (char*)val);
498 case PROCESSING_INSTRUCTION_NODE:
504 switch(v -> vt & VT_BASE)
510 GP( Expression ) e = new Expression(*toE(v), EXF_LOCPATH);
511 (*e).setLS(AXIS_CHILD, EXNODE_NODE);
514 E( (*e).createContext(S, newc) );
516 E( execute(S, NULL, newc, resolvingGlobals) );
517 newc.keep(); // GP: it's NULL by this time anyway
522 //copy contents to output
525 E( v -> value(S, temp, c) );
526 E( outputter() -> eventData(S, temp) );
537 /*................................................................
539 RETURN: pointer to the current mode which is a QName
540 ................................................................*/
542 QName* Processor::getCurrentMode()
544 return (modes.number() ? modes.last() : NULL);
547 /*................................................................
549 called before every mode-changing apply-templates
551 m the mode to be placed on top of the mode stack
552 ................................................................*/
554 void Processor::pushMode(QName *m)
559 /*................................................................
561 called after every mode-changing apply-templates
562 removes the current mode from the mode stack FREEING it
563 ................................................................*/
565 void Processor::popMode()
567 modes.freelast(FALSE);
570 eFlag Processor::addLineNoTree(Sit S, DataLine *&d, Str &absolute, Bool isXSL)
573 M( S, d_ = new DataLine );
574 E( (*d_).open(S, absolute, DLMODE_READ, &argList) );
575 E( datalines.addLine(S, d_, NULL, isXSL) );
580 eFlag Processor::addLineTreeOnly(Sit S, DataLine *&d, Str &absolute, Bool isXSL,
584 M( S, d_ = new DataLine );
585 E( (*d_).setURIAndClose(S, absolute) );
586 E( datalines.addLine(S, d_, t, isXSL, /* preparsedTree = */ TRUE) );
591 eFlag Processor::addLineParse(Sit S, Tree *& newTree, Str &absolute,
592 Bool isXSL, Bool ignoreErr /* = FALSE */)
594 GP( DataLine ) d = new DataLine;
595 E( (*d).open(S, absolute, DLMODE_READ, &argList, ignoreErr) );
596 GP( Tree ) newTree_ = new Tree(absolute, isXSL );
597 //E( (*newTree_).parse(S, d) );
598 eFlag status = (*newTree_).parse(S, d);
600 //hold parse errors after dataline is closed
602 E( datalines.addLine(S, d.keep(), newTree = newTree_.keep(), isXSL) );
606 const Str& Processor::findBaseURI(Sit S, const Str& unmappedBase)
609 uri2SchemePath(S, unmappedBase, scheme, rest);
610 Str *mapping = baseURIMappings.find(scheme);
611 if (mapping) return *mapping;
612 mapping = baseURIMappings.find(""/**theEmptyString*/);
613 if (mapping) return *mapping;
618 // Processor::baseForVertex
620 // returns the *translated* base URI in effect for a given vertex
623 const Str& Processor::baseForVertex(Sit S, Element *v)
625 return findBaseURI(S, NZ(v) -> getSubtreeInfo() -> getBaseURI());
630 // Processor::readTreeFromURI
632 // reads in a tree from URI 'location' resolved against 'base' which is
633 // a *translated* base (one for which the 'hard base URIs' have been taken
637 eFlag Processor::readTreeFromURI(Sit S, Tree*& newTree, const Str& location,
638 const Str& base, Bool isXSL,
639 Bool ignoreErr /* = FALSE */)
643 makeAbsoluteURI(S, location, base, absolute);
644 newTree = datalines.getTree(absolute, isXSL, DLMODE_READ);
646 E( addLineParse(S, newTree, absolute, isXSL, ignoreErr) );
650 eFlag Processor::createOutputterForURI(Sit S, Str& location, Str& base,
651 OutputterObj*& result,
652 OutputDefinition *outDef /*=null*/)
655 makeAbsoluteURI(S, location, base, absolute);
656 if (datalines.getTree(absolute, FALSE, DLMODE_WRITE))
657 Err1(S, E1_URI_WRITE, absolute);
659 if ( !(absolute == "arg:/null") ) {
660 M( S, d = new DataLine );
661 E( (*d).open(S, absolute, DLMODE_WRITE, &argList) );
662 // FIXME: the NULL tree in the following
663 E( datalines.addLine(S, d.keep(), NULL, FALSE) );
664 }else{ //physical output not required
667 GP( OutputterObj ) newOut;
668 M( S, newOut = new OutputterObj );
670 if (!outDef) outDef = &(styleSheet -> outputDef);
671 E( (*newOut).setOptions(S, d, outDef) );
673 E( (*newOut).setOptionsSAX(S, theSAXHandler, theSAXUserData,
674 SAXOUTPUT_AS_PHYSICAL) );
676 result = newOut.keep();
681 eFlag Processor::createOutputDocument(Sit S, Str& href,
682 OutputDocument *&resultDoc,
683 OutputDefinition *def)
686 //OutputterObj *newOut;
687 //E( createOutputterForURI(S, href, base, newOut, def) );
689 //GP(OutputDocument) doc = new OutputDocument(newOut, def);
690 GP(OutputDocument) doc = new OutputDocument(href, def);
692 resultDoc = doc.keep();
693 outputDocuments.append(resultDoc);
698 eFlag Processor::startDocument(Sit S, OutputDocument *doc)
700 switch (doc -> getState()) {
703 OutputterObj *out = NZ( doc -> getOutputter());
704 E( pushOutputter(S, out) );
708 ////////////////////////////////////////
709 //create the outputter
710 Str &href = doc -> getHref();
712 OutputterObj *current = outputter();
713 PhysicalOutputLayerObj *phys;
714 if (current && (phys = current->getPhysical()) && phys->getDataLine())
716 base = phys -> getDataLine() -> fullUri;
718 if (base == "" || base == "file://stdout" || base == "file://stderr")
724 S.message(MT_LOG, L2_SUBDOC_BASE, href, base);
726 S.message(MT_LOG, L2_SUBDOC, href, base);
728 OutputterObj *newOut;
729 E( createOutputterForURI(S, href, base, newOut, doc->getDefinition()) );
730 E( pushOutputter(S, doc -> setOutputter(newOut)) );
731 E( outputter() -> eventBeginOutput(S) );
733 doc -> setState(OUTDOC_ACTIVE);
735 case OUTDOC_FINISHED:
736 assert(! "Couldn't write the document twice"); break;
741 eFlag Processor::finishDocument(Sit S, OutputDocument *doc, Bool canClose)
743 switch (doc -> getState()) {
745 case OUTDOC_FINISHED:
746 assert(!"Could not finish unopened/finished document"); break;
751 E( outputter() -> eventTrailingNewline(S) );
752 E( outputter() -> eventEndOutput(S) );
753 doc -> setState(OUTDOC_FINISHED);
755 E( popOutputterNoFree(S) );
761 eFlag Processor::pushOutputterForURI(Sit S, Str& location, Str& base,
762 OutputDefinition *outDef /*=NULL*/)
764 OutputterObj *newOut;
766 E( createOutputterForURI(S, location, base, newOut, outDef) );
768 outputters_.append(newOut);
772 eFlag Processor::pushTreeConstructer(Sit S, TreeConstructer *& newTC, Tree *t,
776 GP( TreeConstructer ) newTC_ = new TreeConstructer(S);
777 GP( OutputterObj ) newTCSource = new OutputterObj;
778 //E( (*newTCSource).setOptions(S, NULL, &(styleSheet -> outputDef)) ); //_PH_
780 outputters_.append(newTCSource);
781 E( (*newTC_).parseUsingSAX(S, t, *newTCSource, ot) );
783 newTC = newTC_.keep();
787 eFlag Processor::pushOutputter(Sit S, OutputterObj* out_)
789 outputters_.append(out_);
793 eFlag Processor::popOutputter(Sit S)
795 outputters_.freelast(FALSE);
799 eFlag Processor::popOutputterNoFree(Sit S)
801 outputters_.deppend();
805 eFlag Processor::popTreeConstructer(Sit S, TreeConstructer *theTC)
813 eFlag Processor::parse(Sit S, Tree *t, DataLine *d)
815 Log1(S, L1_PARSING, t -> name);
816 double time_was = getMillisecs();
817 TreeConstructer tc(S);
818 eFlag retval = tc.parseDataLineUsingExpat(S, t, d);
821 Log1(S, L1_PARSE_DONE, getMillisecsDiff(time_was));
827 eFlag Processor::getArg(Sit S, const char* name, char*& buffer, Bool isUTF16)
829 Str temp, *value = argList.find(temp = (char*)name);
831 Err1(S, E1_ARG_NOT_FOUND,(char*) name);
832 buffer = (char*) *value;
839 // plugin handler stuff
844 eFlag Processor::setHandler(Sit S, HandlerType type, void *handler, void *userData)
846 void **whereHandler, **whereUserData;
851 whereHandler = (void **)&theSchemeHandler;
852 whereUserData = &theSchemeUserData;
856 whereHandler = (void **)&theMessageHandler;
857 whereUserData = &theMessageUserData;
861 whereHandler = (void **)&theSAXHandler;
862 whereUserData = &theSAXUserData;
866 whereHandler = (void **)&theMiscHandler;
867 whereUserData = &theMiscUserData;
871 whereHandler = (void **)&theEncHandler;
872 whereUserData = &theEncUserData;
875 Err1(S, E1_INVALID_HLR_TYPE, (int) type);
880 Warn1(S, W1_HLR_REGISTERED, hlrTypeNames[type])
883 *whereHandler = NULL;
884 *whereUserData = NULL;
891 *whereHandler = handler;
892 *whereUserData = userData;
895 Warn1(S, W1_HLR_NOT_REGISTERED, hlrTypeNames[type])
901 SchemeHandler* Processor::getSchemeHandler(void **udata)
904 *udata = theSchemeUserData;
905 return theSchemeHandler;
908 MessageHandler* Processor::getMessageHandler(void **udata)
911 *udata = theMessageUserData;
912 return theMessageHandler;
915 SAXHandler* Processor::getSAXHandler(void **udata)
918 *udata = theSAXUserData;
919 return theSAXHandler;
922 MiscHandler* Processor::getMiscHandler(void **udata)
925 *udata = theMiscUserData;
926 return theMiscHandler;
929 EncHandler* Processor::getEncHandler(void **udata)
932 *udata = theEncUserData;
933 return theEncHandler;
936 void* Processor::getHandlerUserData(HandlerType type, void *handler)
940 case HLR_SCHEME: return theSchemeUserData;
941 case HLR_MESSAGE: return theMessageUserData;
942 case HLR_MISC: return theMiscUserData;
943 default: return theSAXUserData;
947 void Processor::setHardEncoding(const Str& hardEncoding_)
949 hardEncoding = hardEncoding_;
952 const Str& Processor::getHardEncoding() const
957 /*****************************************************************
959 called if the result document's location uses the arg:
960 scheme. Returns information about the associated named buffer.
961 if not found, returns -1 in argOrdinal and NULL in newCopy.
963 argName the name of the arg
965 *argOrdinal the ordinal number of this arg. This is the number
966 of the call to useArg() which defined the arg.
967 newCopy pointer to a new copy of the arg (allocated via
969 *****************************************************************/
971 void Processor::copyArg(Sit S, const Str& argName, int* argOrdinal,
976 if ((makeAbsoluteURI(S, (Str&)argName, "arg:/", absolute) != URI_ARG)
977 || (lineNo = datalines.findNum(absolute, FALSE, DLMODE_WRITE)) == -1)
983 DynBlock *block = NZ( datalines[lineNo] -> _dataline -> getOutBuffer() );
984 newCopy = block -> compactToBuffer(); // GP: OK (no exit route)
987 *argOrdinal = argList.findNum((char *)absolute + 4); // skip 'arg:'
991 eFlag Processor::useArg(Sit S, const char *name, const char *val)
998 if (argList.find(nameStr))
999 Err1(S, E1_DUPLICATE_ARG, nameStr);
1000 StrStr *p = new StrStr;
1012 eFlag Processor::useTree(Sit S, const char *name, Tree *t)
1019 // to check for duplicate trees
1020 E( useArg(S, name, NULL) );
1024 makeAbsoluteURI(S, nameStr, "arg:", absolute);
1025 E( addLineTreeOnly(S, d, absolute, t -> XSLTree, t) );
1030 eFlag Processor::addGlobalParam(Sit S, const char *name, const char *val)
1033 if (!val) val = (char*)"";
1034 globalParamsList.appendConstruct(name, val);
1038 eFlag Processor::useGlobalParam(Sit S, const char *name, const char *val)
1042 q.setLocal(NZ(styleSheet) -> unexpand(name));
1043 Expression *expr = new Expression(styleSheet -> getRoot(), EXF_ATOM);
1045 expr -> setAtom(aux);
1046 vars -> addPrebinding(S, q, expr);
1050 eFlag Processor::useGlobalParams(Sit S)
1052 while (globalParamsList.number())
1054 StrStr& item = *(globalParamsList.last());
1055 E( useGlobalParam(S, item.key, item.value) );
1056 globalParamsList.freelast(FALSE);
1061 void Processor::setHardBaseURI(const char* hardBase)
1063 addBaseURIMapping(""/**theEmptyString*/, (const Str) hardBase);
1066 void Processor::addBaseURIMapping(const Str& scheme, const Str& mapping)
1068 int ndx = baseURIMappings.findNum(scheme);
1070 baseURIMappings.freerm(ndx, FALSE);
1071 if (!mapping.isEmpty())
1072 baseURIMappings.appendConstruct(scheme, mapping);
1075 eFlag Processor::freeResultArgs(Sit S)
1077 datalines.freeall(FALSE);
1078 argList.freeall(FALSE);
1083 SabArena* Processor::getArena()
1088 eFlag Processor::prefixIsAliasTarget(Sit S, const Str& prefix, Bool& result)
1091 //we may enter during the tree copy as well
1094 Phrase p = NZ(styleSheet) -> unexpand(prefix);
1095 for (int i = 0; i < styleSheet -> aliases().number(); i++)
1097 if (styleSheet -> aliases()[i] -> getValue() == p)
1107 void Processor::getAliasedName(EQName & name, Bool & aliased)
1109 Str myUri = name.getUri();
1110 for (int i = 0; i < styleSheet -> aliases().number(); i++)
1112 const Str & aliasUri =
1113 styleSheet -> expand(styleSheet -> aliases()[i]->getKey());
1114 if (aliasUri && aliasUri == myUri)
1116 Phrase newUri = styleSheet -> aliases()[i] -> getValue();
1117 Phrase newPrefix = styleSheet -> aliases()[i] -> getPrefix();
1118 name.setUri(styleSheet -> expand(newUri));
1119 //name.setPrefix(styleSheet -> expand(newPrefix));
1127 Str Processor::getAliasedName(const EQName& name,
1128 NamespaceStack& currNamespaces,
1134 //Bool defaultNS = !name.hasPrefix();
1136 if (1 || name.hasPrefix())
1138 Phrase newPrefix = UNDEF_PHRASE;
1139 Str myUri = name.getUri();
1141 Bool aliasFound = FALSE;
1144 for (i = 0; i < styleSheet -> aliases().number(); i++)
1146 const Str* aliasUri =
1147 currNamespaces.getUri(styleSheet -> expand(
1148 styleSheet -> aliases()[i]->getKey()));
1149 if (aliasUri && *aliasUri == myUri)
1151 newPrefix = styleSheet -> aliases()[i] -> getValue();
1157 if (newPrefix == UNDEF_PHRASE)
1159 if (! aliasFound && name.hasPrefix())
1160 newPrefixStr = name.getPrefix();
1164 newPrefixStr = styleSheet -> expand(newPrefix);
1165 //s += newPrefixStr;
1166 //we should proceed w/o this
1167 //currNamespaces.appendConstruct(name.getPrefix(),name.getUri(),TRUE);
1168 //currNamespaces.appendConstruct(newPrefixStr,
1169 //*currNamespaces.getUri(newPrefixStr));
1171 //if (!s.isEmpty()) // could be empty e.g. for the default namespace
1177 s += THE_NAMESPACE_SEPARATOR;
1178 s += name.getLocal();
1179 s += THE_NAMESPACE_SEPARATOR;
1185 if (! s.isEmpty()) s += ":";
1186 s += name.getLocal();
1192 eFlag Processor::addKey(Sit S, const EQName& ename,
1193 Expression& match, Expression &use)
1196 //E( keys -> addKey(S, ename, toSXP_Document(*input), match, use) );
1197 E( NZ(keys) -> addKey(S, ename, inputRoot, match, use) );
1201 eFlag Processor::getKeyNodes(Sit S, const EQName& ename,
1202 const Str& value, Context& result,
1203 SXP_Document doc) const
1205 E( NZ(keys) -> getNodes(S, ename, doc, value, result) );
1209 eFlag Processor::makeKeysForDoc(Sit S, SXP_Document doc)
1211 E( NZ(keys) -> makeKeysForDoc(S, doc) );
1216 void Processor::report(Sit S, MsgType type, MsgCode code,
1217 const Str &arg1, const Str &arg2) const
1219 S.message(type, code, arg1, arg2);
1222 void Processor::initForSXP(Tree *baseTree)
1225 styleSheet = baseTree;
1226 runsOnExternal = TRUE;
1228 vars = new VarsList(*styleSheet);
1231 void Processor::cleanupAfterSXP()
1233 vars -> freeall(FALSE);
1235 runsOnExternal = FALSE;
1238 Bool Processor::supportsFunction(Str &uri, Str &name)
1241 JSContextItem *item = jscontexts.find(uri, FALSE);
1243 for (int i = 0; i < item -> names.number(); i++) {
1244 if (*(item -> names[i]) == name) return TRUE;
1254 eFlag Processor::evaluateJavaScript(Sit S, Str &uri, DStr &script)
1256 //printf("===> evaluating uri %s: %s\n", (char*)uri, (char*)script);
1258 JSContextItem *item = jscontexts.find(uri, TRUE);
1260 if (item && item -> cx) {
1261 if (! SJSEvaluate(*item, script ) )
1264 msg = msg + (item -> errInfo.message ? item -> errInfo.message : "");
1265 if (item -> errInfo.token) {
1266 msg = msg + "' token: '";
1267 msg = msg + (item -> errInfo.token ? item -> errInfo.token : "");
1270 Err2( S, E_JS_EVAL_ERROR,
1271 Str(item -> errInfo.line), msg );
1278 eFlag Processor::callJSFunction(Sit S, Context *c, Str &uri, Str &name,
1279 ExprList &atoms, Expression &retxpr)
1281 if (supportsFunction(uri, name)) {
1282 JSContextItem *item = jscontexts.find(uri, FALSE);
1284 if (! SJSCallFunction(S, c, *item, name, atoms, retxpr) )
1287 msg = msg + (item -> errInfo.message ? item -> errInfo.message : "");
1288 if (item -> errInfo.token) {
1289 msg = msg + "' token: '";
1290 msg = msg + (item -> errInfo.token ? item -> errInfo.token : "");
1293 Err2( S, E_JS_EVAL_ERROR,
1294 Str(item -> errInfo.line), msg );
1303 Str Processor::getNextNSPrefix()
1306 sprintf(ret, "ns_%d", nsUnique++);
1310 eFlag Processor::resolveGlobal(Sit S, Context *c, QName &name, XSLElement *varElem /* = NULL */)
1312 // if !varElem, we need to ask styleSheet's toplevel var directory
1315 varElem = styleSheet -> findVarInDirectory(name);
1318 // set the variable name from the element
1319 E( varElem -> setLogical(S, name, NZ(varElem -> atts.find(XSLA_NAME)) -> cont, FALSE) );
1323 //we have either the name or the element, if both, the element wins
1325 E( varElem->setLogical(S, name,
1326 NZ(varElem->atts.find(XSLA_NAME))->cont, FALSE) );
1327 //this element must be the same as the varElem if available
1328 XSLElement *aux = styleSheet -> findVarInDirectory(name);
1331 //it should happen only if the caller is XSLElement::execute
1332 //and we have some overriden (import) declaration
1333 //in such a case we simply skip the processing
1334 if (varElem != aux) return OK;
1343 // find the var record for several references
1344 VarBindings* record = vars -> find(name);
1345 // maybe it has a binding defined from a forward reference?
1346 //but it shouldn't happen now, due the ** condition
1347 if (record && vars -> getBinding(record))
1351 // maybe it is an "open toplevel" (currently processed)
1352 if (record && vars -> isOpenGlobal(record))
1355 styleSheet -> expandQStr(name, fullName);
1356 Err1(S, E1_VAR_CIRCULAR_REF, fullName);
1360 // process it normally
1361 E( vars -> openGlobal(S, name, record) );
1362 // varElem's expression will automatically evaluate with "resolvingGlobal"
1363 E( varElem -> execute(S, c, /* resolvingGlobals = */ TRUE) );
1364 E( vars -> closeGlobal(S, record) );
1370 // this is not a global
1372 styleSheet -> expandQStr(name, fullName);
1373 Err1(S, E1_VAR_NOT_FOUND, fullName);
1379 eFlag Processor::resolveGlobals(Sit S, Context *c)
1381 return styleSheet -> resolveGlobals(S, c, this);
1385 eFlag Processor::stripElement(Sit S, Daddy *e)
1387 if (isElement(e) && ! toE(e) -> preserveSpace)
1390 e -> getOwner().expandQ(e -> getName(), ename);
1392 double sprio, pprio;
1393 Bool s = styleSheet -> findStrippedName(ename, sprec, sprio);
1394 Bool p = styleSheet -> findPreservedName(ename, pprec, pprio);
1396 if (s && (!p || sprec < pprec || sprio > pprio))
1398 e -> contents.strip();
1402 //process recursively
1403 for (int i = 0; i < e -> contents.number(); i++)
1405 if (isElement(e -> contents[i]))
1406 E( stripElement(S, toE(e -> contents[i])) );
1411 eFlag Processor::stripTree(Sit S, Tree &tree)
1413 //strip is forbidden
1414 if (S.hasFlag(SAB_DISABLE_STRIPPING)) return OK;
1416 //never strip the tree twice
1417 if (tree.stripped) return OK;
1419 //skip if no definition in the stylesheet
1420 if (!styleSheet -> hasAnyStrippedName() &&
1421 ! styleSheet -> hasAnyPreservedName())
1425 Daddy &d = tree.getRoot();
1426 E( stripElement(S, &d) );
1428 tree.stripped = TRUE;
1433 void Processor::pushInBinding(Bool val)
1435 inBinding.append(val);
1438 void Processor::popInBinding()
1440 inBinding.deppend();
1443 Bool Processor::isInBinding()
1445 return inBinding.number() && inBinding.last();
1448 eFlag Processor::pushDocumentDefinition(Sit S, OutputDefinition *def,
1452 Bool change = !documentDefinitions.number() ||
1453 documentDefinitions.last() != def;
1455 documentDefinitions.append(def);
1459 Str href = "file:///home/pavel/ga/sablot-ext/bin/inner.xml";
1461 E( pushOutputterForURI(S, href, base, def) );
1462 E( outputter() -> eventBeginOutput(S) );
1469 eFlag Processor::popDocumentDefinition(Sit S)
1471 assert(documentDefinitions.number());
1472 OutputDefinition *last = documentDefinitions.last();
1473 documentDefinitions.deppend();
1475 if (!documentDefinitions.number() || documentDefinitions.last() != last)
1477 E( outputter() -> eventTrailingNewline(S) );
1478 E( outputter() -> eventEndOutput(S) );
1479 E( popOutputter(S) );