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
49 #define TREE_ARENA_SIZE 0x10000
50 #define TREE_DICT_LOGSIZE 10
52 //atts cache used for parsing
53 class AttsCache: public PList<Attribute*>
56 AttsCache(): keep(FALSE) {};
57 ~AttsCache() {if (!keep) freeall(FALSE);};
58 void keepThem() { keep = TRUE; };
59 Attribute* find(XSL_ATT what);
60 Attribute* find(const QName& attName);
61 int findNdx(const QName& attName);
68 /****************************************
70 ****************************************/
72 class TmpList : public PList<Vertex *>
77 void append(void *what);
80 // void freeall(SablotSituation s);
81 // void dump(SablotSituation sit, int p=0);
83 int findNum(void *p) const;
88 class StylesheetStructure;
92 // holds information about a document which is (1) xsl:included,
93 // (2) xsl:imported or (3) included as external entity to form a part of
94 // the tree. The SubtreeInfo records are linked to form a tree, each one
95 // holds the base URI, pointer to the associated StylesheetStructure
96 // (only exists for xsl:imports) and 'dependency type' which is
97 // (1), (2) or (3) above (with values XSL_INCLUDE, XSL_IMPORT and XSL_NONE,
104 SubtreeInfo(const Str& baseURI_, XSL_OP dependency_,
105 StylesheetStructure* structure_, Bool inline_) :
106 #ifdef SABLOT_DEBUGGER
109 baseURI(baseURI_), dependency(dependency_), inlineVal(inline_),
110 structure(structure_), parentSubtree(NULL), masterSubtree(NULL) {};
114 XSL_OP getDependency()
115 { return dependency; }
116 StylesheetStructure* getStructure()
117 { return structure; }
118 SubtreeInfo* getParentSubtree()
119 { return parentSubtree; }
120 void setParentSubtree(SubtreeInfo *parentSubtree_)
121 { parentSubtree = parentSubtree_; }
122 SubtreeInfo* getMasterSubtree()
123 { return masterSubtree ? masterSubtree : this; };
124 void setMasterSubtree(SubtreeInfo *mstr)
125 { masterSubtree = mstr; };
126 Bool isInline() { return inlineVal; };
127 UriList &getExcludedNS() { return excludedNS; };
128 void pushNamespaceMarks();
129 void popNamespaceMarks();
130 UriList &getExtensionNS() { return extensionNS; };
132 // this is not thread safe, but it is used by the debugger only,
133 // what is single threaded by default
134 #ifdef SABLOT_DEBUGGER
142 StylesheetStructure* structure;
143 //was not used; now it hold pointer to the closest non-inline tree
144 SubtreeInfo* parentSubtree;
145 SubtreeInfo* masterSubtree;
148 List<int> excludedCount;
149 List<int> extensionCount;
152 // the list of subtrees
153 // although a list, it also has a rooted tree structure
155 class SubtreeList : public PList<SubtreeInfo*>
163 // append subtree to list, make it current in the tree structure
164 void push(SubtreeInfo* newSub)
167 NZ(newSub) -> setParentSubtree(currentSub);
171 // go one level higher in the tree structure (but keep subtree in list!)
175 SubtreeInfo *was = currentSub;
176 currentSub = currentSub -> getParentSubtree();
180 // get current subtree
181 SubtreeInfo* getCurrent()
186 SubtreeInfo* findAmongPredecessors(const Str& uri)
189 for (SubtreeInfo* i = currentSub -> getParentSubtree();
191 i = i -> getParentSubtree() )
192 if (i -> getBaseURI() == uri)
198 SubtreeInfo* currentSub;
204 // list of top-level variables and params used to find those of
205 // highest import precedence, while checking for duplicates in
206 // each source document
209 class VarDirectoryItem
212 VarDirectoryItem(QName &name_, XSLElement *varElem_)
213 : varElem(varElem_), name(name_)
215 XSLElement* getElement()
217 void setElement(XSLElement *varElem_)
218 { varElem = varElem_; }
219 const QName &getName()
221 void setName(const QName &name_)
228 class VarDirectory : public PList<VarDirectoryItem*>
232 // kills all VarDirectoryItems
234 // find the var/param of the given QName (relative to the stylesheet
235 // dictionary), NULL if not found
236 XSLElement* find(QName& name);
237 // insert the var/param (overwriting any previous entry of the same name)
238 eFlag insert(Sit S, QName &name, XSLElement* var);
240 // find index of entry with the given QName, -1 if not found
241 int findNdx(const QName& name);
242 void report(Sit S, MsgType type, MsgCode code,
243 const Str &arg1, const Str &arg2) const
244 { S.message(type, code, arg1, arg2); }
247 class SpaceNameList : public PList<EQName*>
250 Bool findName(EQName &ename, double &prio);
253 /****************************************
256 Holds information about the stylesheet tree (pointers
257 to template rules etc.)
258 Created when a document is parsed as stylesheet.
259 The 'imports' list points to structures for all
260 imported stylesheets (these form a tree).
261 ****************************************/
263 class StylesheetStructure
266 StylesheetStructure(int importPrecedence_)
267 : importPrecedence(importPrecedence_), topLevelFound(false) {};
268 ~StylesheetStructure()
270 importChildren.freeall(FALSE);
271 // rulesList.freeall(FALSE); - done in ~RuleSList
272 strippedNamesList.freeall(FALSE);
273 preservedNamesList.freeall(FALSE);
279 Finds the rule of highest import precedence and highest priority
280 that is satisfied by the current node of the context c. If
281 several rules are satisfied, returns the one that occurs last.
282 The current mode is given in currMode (may be NULL). The result,
283 a pointer to the template rule node, is returned in ret.
285 If no rule is found, asks the structures for imported stylesheets.
286 If this doesn't yield a match too, returns NULL.
288 If 'importsOnly' is true, looks only at the imported stylesheets.
290 ASSUMPTION: 'rules' is sorted by priority in reverse order.
293 eFlag findBestRule(Sit S, XSLElement *&ret, Context *c,
294 QName *currMode, Bool importsOnly);
296 // finds the rule of given name with highest import precedence
297 // 't' is the stylesheet
298 XSLElement* findRuleByName(Tree& t, QName &q);
300 // return the list of template rules from this structure
302 { return rulesList; }
304 // insert a template rule into 'rulesList'
305 // the rule is given as a pointer to the corresponding xsl:template
306 eFlag insertRule(Sit S, XSLElement *tmpl);
308 // add structure for imported stylesheet
309 void addImportStructure(Sit S, StylesheetStructure *imported)
310 //{ importChildren.append(imported); }
311 { importChildren.insertBefore(imported, 0); }
313 // get the import precedence associated with this imported subtree
314 int getImportPrecedence()
315 { return importPrecedence; }
317 //set the import precedence
318 void setImportPrecedence(int prec)
319 { importPrecedence = prec; }
321 SpaceNameList &strippedNames() { return strippedNamesList; }
322 SpaceNameList &preservedNames() { return preservedNamesList; }
323 Bool findStrippedName(EQName &ename, int &prec, double &prio);
324 Bool findPreservedName(EQName &ename, int &prec, double &prio);
325 Bool hasAnyStripped();
326 Bool hasAnyPreserved();
327 Bool getTopLevelFound() { return topLevelFound; };
328 void setTopLevelFound(Bool val) { topLevelFound = val; }
330 PList<StylesheetStructure*> importChildren;
332 SpaceNameList strippedNamesList;
333 SpaceNameList preservedNamesList;
334 int importPrecedence;
335 Bool topLevelFound; //used during the xslt parse only, thread safe
336 void report(Sit S, MsgType type, MsgCode code,
337 const Str &arg1, const Str &arg2) const
338 { S.message(type, code, arg1, arg2); }
341 /****************************************************************
345 *****************************************************************/
350 AttSetMember(QName &attName_)
351 : attDef(NULL), redefinition(NULL),
352 attName(attName_), precedence(-1) {};
353 XSLElement* getAttributeDef()
355 // see if there was multiple definition with highest import precedence
356 XSLElement* getRedefinition()
357 {return redefinition;}
361 // sets to a new value if importPrecedence is smaller (stronger)
362 // sets 'redefinition' if equal precedence
363 void set(XSLElement *newAttDef);
372 class AttSet : public PList<AttSetMember*>
375 AttSet(QName &name_);
377 void insertAttributeDef(XSLElement *attDef, QName &attName);
378 void insertUses(QName &usedSet);
379 const QName& getName()
381 eFlag checkRedefinitions(Sit S);
382 // execute the attribute set
383 eFlag execute(Sit S, Context *c, Tree& sheet,
384 QNameList& history, Bool resolvingGlobals);
385 int findNdx(QName &attName);
389 void report(Sit S, MsgType type, MsgCode code,
390 const Str &arg1, const Str &arg2) const
391 { S.message(type, code, arg1, arg2); }
394 class AttSetList : public PList<AttSet*>
399 // check all attribute sets for multiply defined attributes
400 eFlag checkRedefinitions(Sit S);
401 // insert an AttSet named 'name' and return pointer (the set may already exist)
402 AttSet* insert(QName& name);
403 eFlag executeAttSet(Sit S, QName &name, Context *c, Tree &sheet,
404 QNameList& history, Bool resolvingGlobals);
405 AttSet* findByName(const QName &name) const
406 { int ndx = findNdx(name); return (ndx == -1) ? NULL : (*this)[ndx]; }
408 int findNdx(const QName &name) const;
409 void report(Sit S, MsgType type, MsgCode code,
410 const Str &arg1, const Str &arg2) const
411 { S.message(type, code, arg1, arg2); }
417 // records one alias for use in AliasPrecList
418 // holds the key-value pair, checks import precedence on setting
426 :key(UNDEF_PHRASE), value(UNDEF_PHRASE), prefix(UNDEF_PHRASE),
427 precedence(-1), redefinition(NULL) {};
428 Phrase getKey() {return key;}
429 Phrase getValue() {return value;}
430 Phrase getPrefix() {return prefix;}
432 // see if there was multiple definition with highest import precedence
433 XSLElement* getRedefinition()
434 {return redefinition;}
435 // sets to a new value if newPrecedence is smaller (stronger)
436 // sets 'redefinition' if precedences were equal (typically an error)
437 // but sets key/value anyway
438 void set(Phrase newKey, Phrase newValue, Phrase newPrefix,
439 int newPrecedence, XSLElement *source);
441 Phrase key, value, prefix;
443 XSLElement *redefinition;
449 // list of namespace aliases defined by xsl:namespace-alias
450 // checks import precedence when inserting
454 class AliasList : public PList<AliasItem*>
457 // find the value of the element with the given key
458 Phrase find(Phrase) const;
459 // insert an alias (or overwrite old if precedence is not weaker)
460 void insertAlias(Phrase key, Phrase value, Phrase prefix, int precedence,
462 eFlag checkRedefinitions(Sit S, Tree &sheet);
464 // find the index of the element with the given key
465 int findNdx(Phrase) const;
466 void report(Sit S, MsgType type, MsgCode code, const Str &arg1,
467 const Str &arg2) const
468 { S.message(type, code, arg1, arg2); }
474 /****************************************
477 Represents a XML tree in memory. Created by parsing a document.
478 A tree can be used in several processing sessions and even by
479 several threads, so it SHOULD NOT CHANGE during processing (in other
480 words, it holds information which is static with respect to processing).
481 ****************************************/
486 // pass the URI of the tree's document
487 // isXSL_ = TRUE iff the tree represents a stylesheet
488 Tree(const Str& uri, Bool isXSL_);
491 eFlag appendVertex(Sit S, Vertex *);
493 Vertex* appendText(Sit S, char *, int);
494 eFlag parseFinished(Sit S);
497 NSList &pendingNS() {return *(pendingNSList.last());};
498 void dropCurrentElement(Vertex *);
499 void flushPendingText();
500 Element& dummyElement() const;
502 SabArena& getArena();
503 const QName& getTheEmptyQName() const;
504 Phrase stdPhrase(StandardPhrase phrase_) const
506 assert(phrase_ <= PHRASE_LAST);
507 return stdPhrases[phrase_];
509 Bool cmpQNames(const QName &q1, const QName &q2) const;
510 Bool cmpQNamesForeign(const QName &q, const HashTable& dictForeign, const QName &qForeign);
511 Bool cmpQNameStrings(const QName &q, const Str& uri, const Str& local);
512 void expandQ(const QName& q, EQName &expanded);
513 void expandQStr(const QName& q, Str &expName);
514 const Str& expand(Phrase ph);
515 Phrase unexpand(const Str& strg);
516 RootNode& getRoot() const {return* NZ(root);}
517 eFlag serialize(Sit S, char *& result);
518 eFlag serializeNode(Sit S, Element *v, char *& result);
521 //// methods to access stylesheet structure
523 // finds the best matching rule
524 // see StylesheetStructure::findBestRule for description
525 eFlag findBestRule(Sit S, XSLElement *&ret, Context *c,
526 QName *currMode, Bool importsOnly,
527 SubtreeInfo *subtree = NULL);
529 // finds the rule of given name with highest import precedence
530 XSLElement* findRuleByName(QName &q);
533 // returns the list of attribute sets defined
534 AttSetList &attSets()
535 { return attSetList; }
537 // The list of namespace aliases
539 { return aliasesList; }
541 // Output definition holding compiled information from various
542 // xsl:output elements
543 // At runtime, this is copied by Processor and defaults are provided
544 // FOR THE COPY (cannot be guessed at parse time)
545 OutputDefinition outputDef;
547 // this is called after each element has been parsed in
548 // used to compile StylesheetStructure (template rule pointers), process
549 // includes/imports, etc.
550 eFlag processVertexAfterParse(Sit S, Vertex *v, TreeConstructer* tc);
552 // creates this tree by parsing the given dataline
553 eFlag parse(Sit S, DataLine *d);
555 // returns in 'result' the list of elements matching the given expression
556 // used for key creation
557 eFlag getMatchingList(Sit S, Expression& match, Context& result);
559 // find global variable in directory
560 XSLElement* findVarInDirectory(QName &name)
561 { return toplevelVars.find(name); }
563 // the list of temporary nodes which belong to the tree but are not part
564 // of it (used for cleaning up in SDOM)
567 // EXTENSION NAMESPACES
568 // FIXME: efficiency?
569 // FIXME: extension URIs are only valid outside imports/includes!!
570 Bool isExtensionUri(Phrase uri);
571 // MAIN METHODS TO RECORD THE PARSING OF EXTERNAL ENTITIES/INCLUDES/IMPORTS
572 // start a subtree, recording its base URI.
573 // 'dependency' is XSL_NONE (external entity), XSL_INCLUDE or XSL_IMPORT
574 eFlag startSubtree(Sit S, const Str& baseURI, XSL_OP dependency,
575 Bool isInline = FALSE);
577 eFlag endSubtree(Sit S, XSL_OP dependency);
578 // get the tree's URI
581 return subtrees[0] -> getBaseURI();
583 // resolve all global variables before starting execute
584 // called from Processor::resolveGlobals
585 //eFlag resolveGlobals(Sit S, Context *c, Processor *proc);
586 //unparsed entties storge
587 void setUnparsedEntityUri(Str &name, Str &uri);
588 Str* getUnparsedEntityUri(Str &name);
590 Bool hasAnyStrippedName();
591 Bool hasAnyPreservedName();
592 Bool findPreservedName(EQName &name, int &prec, double &prio);
593 Bool findStrippedName(EQName &name, int &prec, double &prio);
594 Element* findStylesheet(Daddy& d);
595 eFlag pushPendingNS(Sit S, Tree* srcTree, NSList &other);
596 eFlag popPendingNS(Sit S);
597 SubtreeInfo* getRootSubtree() { return subtrees[0]; }
598 SubtreeInfo* getCurrentInfo()
599 {return subtrees.getCurrent()->getMasterSubtree();}
600 eFlag markNamespacePrefixes(Sit S);
601 eFlag pushNamespacePrefixes(Sit, Str&, XSL_ATT);
602 eFlag popNamespacePrefixes(Sit);
603 void updateImportStatus();
607 Text *pendingTextNode;
609 int vcount; // # of vertices in tree
610 Element *theDummyElement;
611 HashTable theDictionary;
612 PList<NSList*> pendingNSList;
613 const QName theEmptyQName;
614 Phrase stdPhrases[PHRASE_LAST];
618 StrStrList unparsedEntities;
619 eFlag insertRule(Sit S, XSLElement *tmpl);
620 eFlag insertAttSet(Sit S, XSLElement *tmpl);
621 double defaultPriorityLP(Expression *);
622 double defaultPriority(XSLElement *);
623 void report(Sit S, MsgType type, MsgCode code, const Str &arg1, const Str &arg2) const
624 { S.message(type, code, arg1, arg2); }
625 eFlag getSpaceNames(Sit S, Element &e, Str &str, SpaceNameList &where);
626 eFlag extractUsedSets(Sit S, Element *e);
627 void excludeStdNamespaces();
628 // create a new structure
629 StylesheetStructure* createStylesheetStructure(Sit S);
631 // the structure information about the stylesheet
632 // (separated for import purposes)
633 StylesheetStructure structure;
636 SubtreeList subtrees;
637 AttSetList attSetList;
638 AliasList aliasesList;
639 VarDirectory toplevelVars;
640 int hasAnyStripped, hasAnyPreserved;
644 #endif //ifndef TreeHIncl