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
38 /* ------------------------------------------------------------ */
40 /* -------------------------------------------------------------*/
42 Bool SpaceNameList::findName(EQName &ename, double &prio)
47 for (int i = 0; i < num; i++)
49 EQName *aux = operator[](i);
50 if (aux -> getLocal() == (const char*) "*")
52 if (aux -> getUri() == (const char*) "")
58 if (ename.getUri() == aux -> getUri())
66 if (ename.getLocal() == aux -> getLocal() &&
67 ename.getUri() == aux -> getUri())
71 break; //exit loop, we can't get better match
78 /* ------------------------------------------------------------ */
79 /* StylesheetStructure */
80 /* -------------------------------------------------------------*/
88 SubtreeInfo::~SubtreeInfo()
90 excludedNS.deppendall();
91 extensionNS.deppendall();
92 excludedCount.deppendall();
93 extensionCount.deppendall();
96 void SubtreeInfo::pushNamespaceMarks()
98 excludedCount.append(excludedNS.number());
99 extensionCount.append(extensionNS.number());
102 void SubtreeInfo::popNamespaceMarks()
105 int limit = excludedCount.number() ? excludedCount.last() : 0;
107 for (idx = excludedNS.number() - 1; idx >= limit; idx--)
108 excludedNS.deppend();
109 if (excludedCount.number()) excludedCount.deppend();
111 limit = extensionCount.number() ? extensionCount.last() : 0;
112 for (idx = extensionNS.number() - 1; idx >= limit; idx--)
113 extensionNS.deppend();
114 if (extensionCount.number()) extensionCount.deppend();
119 // StylesheetSructure
123 eFlag StylesheetStructure::findBestRule(
132 // if we don't process imports only, look at the rules in this
136 int rulesNumber = rulesList.number();
139 Expression *pattern = NULL;
142 for (i = 0; i < rulesNumber; i++)
146 (fcomp(rulesList[i] -> priority, bestPrio) == -1)
150 therule = rulesList[i] -> rule;
151 Attribute *a = rulesList[i] -> match;
157 thisMode = rulesList[i] -> mode;
158 if ((!thisMode) ^ (!currMode))
160 if (thisMode && !((*thisMode) == (*currMode)))
162 // else both thisMode and currMode are NULL which is OK
166 E( pattern -> matchesPattern(S, c, result) );
170 bestPrio = rulesList[i] -> priority;
175 ret = rulesList[bestRule] -> rule; // else remains NULL
178 // if no match was found, look at the imported stylesheets
181 int importCount = importChildren.number();
182 for (i = 0; i < importCount && !ret; i++)
184 // call findBestRule recursively, setting importsOnly to FALSE
185 E( importChildren[i] -> findBestRule(
186 S, ret, c, currMode, FALSE));
192 XSLElement* StylesheetStructure::findRuleByName(Tree &t, QName &q)
194 XSLElement* ret = rulesList.findByName(t,q);
195 int importCount = importChildren.number(),
197 for (i = 0; !ret && i < importCount; i++)
198 ret = importChildren[i] -> rulesList.findByName(t,q);
202 Bool StylesheetStructure::hasAnyStripped()
204 Bool ret = strippedNamesList.number();
207 int importCount = importChildren.number();
208 for (int i = 0; i < importCount && !ret; i++)
210 ret = importChildren[i] -> hasAnyStripped();
216 Bool StylesheetStructure::hasAnyPreserved()
218 Bool ret = preservedNamesList.number();
221 int importCount = importChildren.number();
222 for (int i = 0; i < importCount && !ret; i++)
224 ret = importChildren[i] -> hasAnyPreserved();
230 Bool StylesheetStructure::findStrippedName(EQName &ename, int &prec, double &pri)
233 if (strippedNamesList.findName(ename, pri)) {
234 prec = importPrecedence;
239 int importCount = importChildren.number();
240 for (int i = 0; i < importCount && !ret; i++)
242 // call findBestRule recursively, setting importsOnly to FALSE
243 ret = importChildren[i] -> findStrippedName(ename, prec, pri);
249 Bool StylesheetStructure::findPreservedName(EQName &ename, int &prec, double &pri)
252 if (preservedNamesList.findName(ename, pri)) {
253 prec = importPrecedence;
258 int importCount = importChildren.number();
259 for (int i = 0; i < importCount && !ret; i++)
261 // call findBestRule recursively, setting importsOnly to FALSE
262 ret = importChildren[i] -> findPreservedName(ename, prec, pri);
282 VarDirectory::VarDirectory()
286 VarDirectory::~VarDirectory()
291 XSLElement* VarDirectory::find(QName& name)
293 int i = findNdx(name);
294 return (i == -1)? NULL : (*this)[i] -> getElement();
297 eFlag VarDirectory::insert(Sit S, QName &name, XSLElement* var)
299 int i = findNdx(name);
301 append(new VarDirectoryItem(name, var));
304 // if precedences are equal, raise error
306 oldPrec = (*this)[i] -> getElement() -> getImportPrecedence(),
307 newPrec = var -> getImportPrecedence();
308 // due to immediate resolution of xsl:import, new must be <= old
309 assert(newPrec <= oldPrec);
310 (*this)[i] -> setElement(var);
311 if (newPrec == oldPrec)
314 var -> getOwner().expandQStr(name, fullName);
315 Err1(S, E1_MULT_ASSIGNMENT, fullName);
322 int VarDirectory::findNdx(const QName& name)
325 for (i = 0; i < number(); i++)
327 if ( (*this)[i] -> getName() == name )
333 /*****************************************************************
337 *****************************************************************/
341 // AttSetMember implementation
345 void AttSetMember::set(XSLElement *newAttDef)
347 int oldPrec = attDef ?
348 attDef -> getImportPrecedence() : -1;
349 int newPrec = newAttDef -> getImportPrecedence();
350 if (oldPrec == newPrec && !redefinition)
351 redefinition = newAttDef;
352 if (newPrec <= oldPrec || oldPrec == -1)
354 if (newPrec < oldPrec)
364 AttSet::AttSet(QName &name_)
372 //don't free this list items, these are copies of
373 //pointers stored with xsl:attribute-set element
374 //usedSets.freeall(FALSE);
375 usedSets.deppendall();
378 eFlag AttSet::checkRedefinitions(Sit S)
380 for (int i = 0; i < number(); i++)
381 if ((*this)[i] -> getRedefinition())
383 XSLElement *redef = (*this)[i] -> getRedefinition();
384 Str fullNameAtt, fullNameThis;
385 redef -> getOwner().expandQStr((*this)[i] -> getAttName(), fullNameAtt);
386 redef -> getOwner().expandQStr(getName(), fullNameThis);
387 S.setCurrVDoc(redef);
388 Warn2(S, W2_ATTSET_REDEF, fullNameAtt, fullNameThis);
393 eFlag AttSet::execute(Sit S, Context *c, Tree& sheet, QNameList& history, Bool resolvingGlobals)
395 if (history.findNdx(name) != -1)
398 sheet.expandQStr(name, fullName);
399 Err1(S, E1_CIRCULAR_ASET_REF, fullName);
401 history.append(&name);
403 for (i = 0; i < usedSets.number(); i++)
404 E( sheet.attSets().executeAttSet(S, *(usedSets[i]), c,
405 sheet, history, resolvingGlobals) );
408 for (i = 0; i < number(); i++)
410 XSLElement *def = (*this)[i] -> getAttributeDef();
411 //execute the content
412 E( def -> execute(S, c, resolvingGlobals) );
417 int AttSet::findNdx(QName &attName)
419 for (int i = 0; i < number(); i++)
420 if ((*this)[i] -> getAttName() == attName)
425 void AttSet::insertAttributeDef(XSLElement *attDef, QName &attName)
427 int ndx = findNdx(name);
430 append(new AttSetMember(attName));
433 (*this)[ndx] -> set(attDef);
436 void AttSet::insertUses(QName &usedSet)
438 if (usedSets.findNdx(usedSet) == -1)
439 usedSets.append(&usedSet);
449 AttSetList::AttSetList()
451 PList<AttSet*>(LIST_SIZE_LARGE)
454 AttSetList::~AttSetList()
459 eFlag AttSetList::checkRedefinitions(Sit S)
461 for (int i = 0; i < number(); i++)
462 E( (*this)[i] -> checkRedefinitions(S) );
466 AttSet* AttSetList::insert(QName &name)
468 int ndx = findNdx(name);
471 append(ptr = new AttSet(name));
477 eFlag AttSetList::executeAttSet(Sit S, QName &name, Context *c, Tree &sheet, QNameList& history, Bool resolvingGlobals)
479 int ndx = findNdx(name);
483 sheet.expandQStr(name, fullName);
484 Err1(S, E1_NONEX_ASET_NAME, fullName);
486 E( (*this)[ndx] -> execute(S, c, sheet, history, resolvingGlobals) );
490 int AttSetList::findNdx(const QName &what) const
492 int count = number();
493 for (int i = 0; i < count; i++)
494 if ((*this)[i] -> getName() == what)
501 // AliasItem implementation
505 void AliasItem::set(Phrase newKey, Phrase newValue, Phrase newPrefix,
506 int newPrecedence, XSLElement *source)
508 assert(newPrecedence >= 0);
509 if (key == UNDEF_PHRASE) key = newKey;
510 if (precedence == newPrecedence && value != newValue && !redefinition)
511 redefinition = source;
512 if (newPrecedence <= precedence || precedence == -1)
515 precedence = newPrecedence;
518 if (newPrecedence < precedence)
524 // AliasList implementation
528 int AliasList::findNdx(Phrase key_) const
530 int i, count = number();
531 for (i = 0; (i < count) && !(key_ == ((*this)[i] -> getKey())); i++);
532 return (i < count) ? i : -1;
535 Phrase AliasList::find(Phrase key_) const
537 int ndx = findNdx(key_);
538 return (ndx != -1) ? (*this)[ndx] -> getValue() : PHRASE_NOT_FOUND;
541 void AliasList::insertAlias(Phrase key, Phrase value, Phrase prefix,
542 int precedence, XSLElement *source)
545 int ndx = findNdx(key);
547 append(newItem = new AliasItem);
549 newItem = (*this)[ndx];
550 newItem -> set(key, value, prefix, precedence, source);
553 eFlag AliasList::checkRedefinitions(Sit S, Tree &sheet)
555 for (int i = 0; i < number(); i++)
556 if ((*this)[i] -> getRedefinition())
558 S.setCurrVDoc((*this)[i] -> getRedefinition());
560 sheet.expand((*this)[i] -> getKey());
561 Warn1(S, W1_ALIAS_REDEF, fullName);
566 /****************************************
568 ****************************************/
570 Tree::Tree(const Str &aname, BOOL aXSLTree)
571 : theArena(TREE_ARENA_SIZE), theDictionary(&theArena, TREE_DICT_LOGSIZE),
574 // theDictionary.initialize();
575 QName &rootname = (QName&) getTheEmptyQName();
576 root = new(&theArena) RootNode(*this, rootname);
578 stackTop = &getRoot();
579 pendingTextNode = NULL;
583 theDummyElement = new(&theArena) Element(*this, dummyName);
586 // append entry for 'the whole tree' to subtrees
587 subtrees.push(new SubtreeInfo(
588 aname, XSL_NONE, &structure, FALSE));
589 getRoot().setSubtreeInfo(subtrees.last());
591 excludeStdNamespaces();
593 pendingNSList.append(new(&theArena) NSList());
596 hasAnyStripped = hasAnyPreserved = -1;// means 'who knows?'
597 importUnique = 0xFFFF;
602 getRoot().~RootNode();
603 // this is just in case there's a processing error:
604 //pendingNSList.freeall(FALSE);
605 delete theDummyElement;
606 // clear subtree information
607 subtrees.freeall(FALSE);
608 aliasesList.freeall(FALSE);
609 unparsedEntities.freeall(FALSE);
611 pendingNSList.freelast(FALSE);
612 //assert(!pendingNSList.number());
615 void Tree::initDict()
617 theDictionary.initialize();
618 theDictionary.insert("", stdPhrases[PHRASE_EMPTY]);
619 theDictionary.insert("xsl", stdPhrases[PHRASE_XSL]);
620 theDictionary.insert(theXSLTNamespace, stdPhrases[PHRASE_XSL_NAMESPACE]);
621 theDictionary.insert(theXMLNamespace, stdPhrases[PHRASE_XML_NAMESPACE]);
622 theDictionary.insert(theSabExtNamespace, stdPhrases[PHRASE_SABEXT_NAMESPACE]);
623 theDictionary.insert("*", stdPhrases[PHRASE_STAR]);
624 theDictionary.insert("xmlns", stdPhrases[PHRASE_XMLNS]);
625 theDictionary.insert("lang", stdPhrases[PHRASE_LANG]);
628 void Tree::excludeStdNamespaces()
630 NZ(getCurrentInfo()) ->
631 getExcludedNS().addUri(stdPhrase(PHRASE_XML_NAMESPACE));
634 NZ(getCurrentInfo()) ->
635 getExcludedNS().addUri(stdPhrase(PHRASE_XSL_NAMESPACE));
639 Element &Tree::dummyElement() const
641 return *theDummyElement;
644 void Tree::flushPendingText()
647 pendingTextNode -> cont = pendingText;
649 pendingTextNode = NULL;
652 eFlag Tree::appendVertex(Sit S, Vertex *v)
654 assert(stackTop && isDaddy(stackTop));
655 assert(!isText(v) || !pendingTextNode);
658 E( cast(Daddy*,stackTop) -> newChild(S, v) ); //sets parent too
661 v -> stamp = vcount++;
662 // set the subtree information for vertex
663 v -> setSubtreeInfo(subtrees.getCurrent());
667 void Tree::dropCurrentElement(Vertex *v)
669 assert(stackTop && isElement(stackTop));
670 assert(stackTop == v);
671 assert(!pendingTextNode);
672 stackTop = v -> parent;
674 toE(stackTop) -> contents.deppend();
677 Vertex* Tree::appendText(Sit S, char *string, int len)
680 if (!pendingTextNode)
682 // the initializing text does not matter
683 txt = new(&getArena()) Text(*this, string, len);
684 Processor *proc = S.getProcessor();
685 if ( proc && proc->outputter() )
687 OutputDocument *doc=proc->outputter()->getDocumentForLevel(FALSE);
688 txt -> setOutputDocument(doc);
691 appendVertex(S, txt);
692 pendingTextNode = toText(txt);
694 pendingText.nadd(string,len);
698 Vertex* Tree::popVertex()
700 Vertex *v = NZ( stackTop );
701 stackTop = v -> parent;
705 eFlag Tree::parseFinished(Sit S)
711 HashTable& Tree::dict()
713 return theDictionary;
716 SabArena& Tree::getArena()
721 const QName& Tree::getTheEmptyQName() const
723 return theEmptyQName;
727 Bool Tree::cmpQNames(const QName &first, const QName &second) const
730 printf("comparing names (%s,%s,%s) and (%s,%s,%s)\n",
731 (char*)(((Tree*)this)->expand(first.getPrefix())),
732 (char*)(((Tree*)this)->expand(first.getUri())),
733 (char*)(((Tree*)this)->expand(first.getLocal())),
734 (char*)(((Tree*)this)->expand(second.getPrefix())),
735 (char*)(((Tree*)this)->expand(second.getUri())),
736 (char*)(((Tree*)this)->expand(second.getLocal()))
739 if (first.getLocal() == stdPhrase(PHRASE_STAR))
740 return (Bool)(first.getPrefix() == UNDEF_PHRASE ||
741 first.getUri() == second.getUri());
743 return (Bool) (first.getUri() == second.getUri()
744 && first.getLocal() == second.getLocal());
747 Bool Tree::cmpQNamesForeign(const QName &q, const HashTable& dictForeign, const QName &qForeign)
750 printf("comparing names (%s,%s,%s) and (%s,%s,%s)\n",
751 (char*)(((Tree*)this)->expand(q.getPrefix())),
752 (char*)(((Tree*)this)->expand(q.getUri())),
753 (char*)(((Tree*)this)->expand(q.getLocal())),
754 (char*)(dictForeign.getKey(qForeign.getPrefix())),
755 (char*)(dictForeign.getKey(qForeign.getUri())),
756 (char*)(dictForeign.getKey(qForeign.getLocal()))
760 if (q.getLocal() == stdPhrase(PHRASE_STAR))
762 return (Bool)(q.getPrefix() == UNDEF_PHRASE ||
763 (dict().getKey(q.getUri()) == dictForeign.getKey(qForeign.getUri())));
768 (dict().getKey(q.getUri()) == dictForeign.getKey(qForeign.getUri()) &&
769 dict().getKey(q.getLocal()) == dictForeign.getKey(qForeign.getLocal()));
773 Bool Tree::cmpQNameStrings(const QName &q, const Str& uri, const Str& local)
775 if (q.getLocal() == stdPhrase(PHRASE_STAR))
777 q.getUri() == UNDEF_PHRASE || dict().getKey(q.getUri()) == uri);
781 (dict().getKey(q.getUri()) == uri &&
782 dict().getKey(q.getLocal()) == local);
786 void Tree::expandQ(const QName& q, EQName& expanded)
788 expanded.setLocal(expand(q.getLocal()));
789 expanded.setUri(expand(q.getUri()));
790 expanded.setPrefix(expand(q.getPrefix()));
793 void Tree::expandQStr(const QName& q, Str& expName)
796 expandQ(q, expanded);
797 expanded.getname(expName);
800 const Str& Tree::expand(Phrase ph)
802 return dict().getKey(ph);
805 Phrase Tree::unexpand(const Str& strg)
808 dict().insert(strg, result);
812 eFlag Tree::serialize(Sit S, char *& result)
815 OutputDefinition def;
816 GP( DataLine ) targetLine = new DataLine;
817 // set default options for output
819 xmlMethod.setLocal((char*)"xml");
820 E( def.setItemEQName(S, XSLA_METHOD, xmlMethod, NULL, OUTPUT_PRECEDENCE_WEAKEST) );
821 E( def.setDefaults(S) );
822 E( (*targetLine).open(S, (const char*)"arg:/dummy_", DLMODE_WRITE, NULL) );
823 out.setOptions(S, targetLine, &def);
824 E( getRoot().serialize(S, out) );
825 result = (*targetLine).getOutBuffer() -> compactToBuffer();
826 E( (*targetLine).close(S) );
831 eFlag Tree::serializeNode(Sit S, Element *v, char *& result)
834 OutputDefinition def;
835 GP( DataLine ) targetLine = new DataLine;
836 // set default options for output
838 xmlMethod.setLocal((char*)"xml");
839 E( def.setItemEQName(S, XSLA_METHOD, xmlMethod, NULL, OUTPUT_PRECEDENCE_WEAKEST) );
840 E( def.setDefaults(S) );
841 E( (*targetLine).open(S, (const char*)"arg:/dummy_", DLMODE_WRITE, NULL) );
842 out.setOptions(S, targetLine, &def);
843 E( (*v).serializeSubtree(S, out) );
844 result = (*targetLine).getOutBuffer() -> compactToBuffer();
845 E( (*targetLine).close(S) );
850 void Tree::makeStamps()
853 getRoot().makeStamps(stamp_);
857 void Tree::updateImportStatus()
859 if (! subtrees.getCurrent() -> getStructure() -> getTopLevelFound() )
861 StylesheetStructure * stru = subtrees.getCurrent() -> getStructure();
862 stru -> setTopLevelFound(true);
863 stru -> setImportPrecedence(importUnique);
868 /*****************************************************************
869 Tree::processVertexAfterParse()
870 Performs any necessary actions on a vertex immediately after it is
871 parsed into the tree. The vertex is still 'current'. Typically, this
872 function calls popVertex.
874 v the vertex to be processed
875 The function operates only on XSL vertices, namely:
876 xsl:include - replaces the vertex by the newly constructed tree
877 xsl:output - files the information into the tree's structures
879 Other vertices are just popped off the stack.
880 *****************************************************************/
882 eFlag Tree::processVertexAfterParse(Sit S, Vertex *v, TreeConstructer* tc)
884 //be careful with this test, it might be moved deeper inside this
887 if (v -> vt & VT_TOP_FOREIGN)
896 XSLElement *x = toX(v);
899 if (theOp != XSL_IMPORT) updateImportStatus();
903 //catch xsl:use-attribute-sets
907 E( extractUsedSets(S, toE(v)) );
912 if (subtrees.getCurrent() -> getStructure() -> getTopLevelFound())
914 Err2(S, E_ELEM_CONTAINS_ELEM,
915 xslOpNames[XSL_STYLESHEET],
916 xslOpNames[XSL_IMPORT]);
921 Attribute *a = NZ( x -> atts.find(XSLA_HREF) );
923 const Str& base = S.findBaseURI(a -> getSubtreeInfo() ->
927 makeAbsoluteURI(S, a -> cont, base, absolute);
928 if (S.getProcessor())
930 E( S.getProcessor() -> readTreeFromURI(S, srcTree,
938 //makeAbsoluteURI(a -> cont, base, absolute);
939 srcTree = new Tree(absolute, FALSE);
941 E( d.open(S, absolute, DLMODE_READ, /* argList = */ NULL) );
942 E( (*srcTree).parse(S, &d) );
946 Element *theSheet=(*srcTree).findStylesheet((*srcTree).getRoot());
948 Warn1(S, W_NO_STYLESHEET, (char*)(a -> cont));
949 dropCurrentElement(v);
952 // we start a subtree to record where the nodes come from
953 // when including, we use the old structure
954 // when importing, Tree creates a new one
955 E( startSubtree(S, (*srcTree).getURI(), theOp) );
956 //set extension namespaces for subtree
958 //(*srcTree).speakDebug();
960 //merge it into the current tree
961 E( tc -> parseUsingSAXForAWhile(S, source, absolute,
964 theSheet -> namespaces) );
966 //first we have to deal with ext. and excl. namespaces
970 q.setLocal((*srcTree).unexpand("exclude-result-prefixes"));
971 attr = theSheet->atts.find(q);
973 E(pushNamespacePrefixes(S, attr->cont, XSLA_EXCL_RES_PREFIXES));
975 q.setLocal((*srcTree).unexpand("extension-element-prefixes"));
976 attr = theSheet->atts.find(q);
978 E(pushNamespacePrefixes(S, attr->cont, XSLA_EXT_ELEM_PREFIXES));
981 E( theSheet -> contents.copy(S, source) );
982 E( tc -> parseUsingSAXForAWhileDone(S, source, TRUE) );
984 E( endSubtree(S, theOp) );
988 int i, attsNumber = x -> atts.number();
990 for (i = 0; i < attsNumber; i++)
992 theAtt = toA(x -> atts[i]);
999 E( x -> setLogical(S,
1000 q, theAtt -> cont, FALSE) );
1002 E( outputDef.setItemEQName(S, XSLA_METHOD,
1004 v -> getImportPrecedence()) );
1006 case XSLA_CDATA_SECT_ELEMS:
1011 char *p = theAtt -> cont;
1014 someRemains = getWhDelimString(p, listPart);
1017 E( x -> setLogical(S,
1018 q, listPart, TRUE) );
1020 expandQ(q, expanded);
1021 E( outputDef.setItemEQName(S,
1022 XSLA_CDATA_SECT_ELEMS,
1024 v -> getImportPrecedence()) );
1027 while (someRemains);
1029 case XSLA_NONE: //skip other namespaces
1033 E( outputDef.setItemStr(S, theAtt -> op, theAtt -> cont,
1035 theAtt -> getImportPrecedence()) );
1042 case XSL_NAMESPACE_ALIAS:
1044 Phrase style, result, sUri, rUri;
1045 Attribute *sp = NZ( x -> atts.find(XSLA_STYLESHEET_PREFIX) );
1046 Attribute *rp = NZ( x -> atts.find(XSLA_RESULT_PREFIX) );
1047 if (sp -> cont == "#default") style = UNDEF_PHRASE;
1048 else dict().insert(sp -> cont, style);
1049 if (rp -> cont == "#default") result = UNDEF_PHRASE;
1050 else dict().insert(rp -> cont, result);
1053 i = pendingNS().findNdx(style);
1055 sUri = toNS(pendingNS().operator[](i)) -> uri;
1057 Err1(S, E_EX_NAMESPACE_UNKNOWN, (char*) sp -> cont);
1059 i = pendingNS().findNdx(result);
1061 rUri = toNS(pendingNS().operator[](i)) -> uri;
1063 Err1(S, E_EX_NAMESPACE_UNKNOWN, (char*) rp -> cont);
1065 aliases().insertAlias(sUri, rUri, result,
1066 v -> getImportPrecedence(), x);
1071 E( insertRule(S, x) );
1074 case XSL_ATTRIBUTE_SET:
1078 E( x -> setLogical(S, name,
1079 NZ( x -> atts.find(XSLA_NAME)) -> cont,
1081 AttSet *ptr = attSets().insert(name);
1082 E( extractUsedSets(S, toE(v)) );
1083 if (x -> attSetNames(FALSE))
1085 for (int i = 0; i < x -> attSetNames(FALSE) -> number(); i++)
1086 ptr -> insertUses(*(x -> attSetNames(FALSE) -> operator[] (i)));
1089 for (int i = 0; i < x -> contents.number(); i++)
1091 assert(isXSLElement(x -> contents[i]) &&
1092 toX(x -> contents[i]) -> op == XSL_ATTRIBUTE);
1093 son = toX(x -> contents[i]);
1094 E( son -> setLogical(S, name,
1095 NZ( son -> atts.find(XSLA_NAME)) -> cont,
1097 ptr -> insertAttributeDef(son, name);
1101 case XSL_STYLESHEET:
1109 // only look at top-levels
1110 Vertex *par = v -> parent;
1111 if (par && isXSLElement(par) &&
1112 (toX(par) -> op == XSL_STYLESHEET ||
1113 toX(par) -> op == XSL_TRANSFORM))
1115 // is top-level -> insert into directory,
1116 //with error if there already is an entry
1117 // with the same import precedence
1120 E( x -> setLogical(S, name,
1121 NZ( x -> atts.find(XSLA_NAME)) -> cont,
1123 E( toplevelVars.insert(S, name, x) );
1127 case XSL_STRIP_SPACE:
1129 SpaceNameList &foo =
1130 subtrees.getCurrent() -> getStructure() -> strippedNames();
1131 E( getSpaceNames(S, *x, NZ(x -> atts.find(XSLA_ELEMENTS)) -> cont,
1135 case XSL_PRESERVE_SPACE:
1137 SpaceNameList &foo =
1138 subtrees.getCurrent() -> getStructure() -> preservedNames();
1139 E( getSpaceNames(S, *x, NZ(x -> atts.find(XSLA_ELEMENTS)) -> cont,
1146 //the literal output element may have some xsl features
1150 updateImportStatus();
1152 E( extractUsedSets(S, toE(v)) );
1162 eFlag Tree::getSpaceNames(Sit S, Element &e, Str &str, SpaceNameList &where)
1168 int i = strcspn(q, theWhitespace);
1177 E( e.setLogical(S, name, token, FALSE) );
1178 GP(EQName) ename = new EQName;
1179 expandQ(name, *ename);
1180 where.append(ename.keep());
1185 i = strcspn(q, theWhitespace);
1191 eFlag Tree::markNamespacePrefixes(Sit S)
1194 getCurrentInfo() -> pushNamespaceMarks();
1198 eFlag Tree::pushNamespacePrefixes(Sit S, Str& prefixes, XSL_ATT att)
1200 if (!XSLTree) return OK;
1204 q = (char*) prefixes;
1207 int i = strcspn(q, theWhitespace);
1214 Str* aux = new Str(p);
1220 i = strcspn(q, theWhitespace);
1223 SubtreeInfo *info = getCurrentInfo();
1224 for (i = 0; i < tokens.number(); i++)
1226 Str tok = *(tokens[i]);
1228 tok == (const char*) "#default" ? UNDEF_PHRASE : unexpand(tok);
1229 int idx = pendingNS().findNdx(prefix);
1233 case XSLA_EXT_ELEM_PREFIXES:
1235 info -> getExtensionNS().append(toNS(pendingNS()[idx]) -> uri);
1237 case XSLA_EXCL_RES_PREFIXES:
1239 info -> getExcludedNS().append(toNS(pendingNS()[idx]) -> uri);
1245 Str aux = *(tokens[i]);
1246 tokens.freeall(FALSE);
1247 Err1(S, E_EX_NAMESPACE_UNKNOWN, (char*) aux);
1250 tokens.freeall(FALSE);
1251 //printf("----------------------------\n");
1255 eFlag Tree::popNamespacePrefixes(Sit S)
1258 getCurrentInfo() -> popNamespaceMarks();
1262 eFlag Tree::extractUsedSets(Sit S, Element *e)
1264 Attribute *a = e -> atts.find(XSLA_USE_ATTR_SETS);
1267 QNameList *names = e -> attSetNames(TRUE);
1268 names -> freeall(FALSE);
1271 q = (char*) (a -> cont);
1274 int i = strcspn(q, theWhitespace);
1281 GP( QName ) name = new QName;
1282 E( e -> setLogical(S, *name, token, FALSE) );
1284 names -> append( name.keep() );
1288 i = strcspn(q, theWhitespace);
1295 /*****************************************************************
1297 finds a xsl:stylesheet child of the given daddy. Returns NULL
1299 *****************************************************************/
1301 Element* Tree::findStylesheet(Daddy& d)
1304 int dContentsNumber = d.contents.number();
1305 for (int i = 0; i < dContentsNumber; i++)
1307 if (isElement(w = d.contents[i]))
1309 const QName& wName = toE(w) -> name;
1310 Tree& owner = w -> getOwner();
1312 // if (!strcmp(wName.getUri(), theXSLTNamespace) && /* _PH_ */
1313 if (wName.getUri() == owner.stdPhrase(PHRASE_XSL_NAMESPACE) &&
1314 ((localStr = owner.expand(wName.getLocal()) ==
1315 xslOpNames[XSL_STYLESHEET]) ||
1316 (localStr == xslOpNames[XSL_TRANSFORM])))
1323 double Tree::defaultPriorityLP(Expression *lpath)
1325 assert(lpath && lpath -> functor == EXF_LOCPATH);
1326 assert(lpath -> args.number());
1327 if ((lpath -> args.number() > 1) || lpath -> args[0] -> step -> preds.number())
1331 switch (lpath -> args[0] -> step -> ntype)
1333 case EXNODE_COMMENT:
1339 return lpath->args[0]->step->piname == "" ? -0.5 : 0;
1342 QName &qn = lpath -> args[0] -> step -> ntest;
1343 if (qn.getLocal() != lpath -> getOwnerTree().stdPhrase(PHRASE_STAR))
1347 if (qn.getPrefix() == UNDEF_PHRASE)
1357 return 0; // BCC thinks we don't return enough
1360 double Tree::defaultPriority(XSLElement *tmpl)
1362 Expression *e = tmpl -> getAttExpr(XSLA_MATCH);
1364 return PRIORITY_NOMATCH;
1365 switch(e -> functor)
1369 return defaultPriorityLP(e);
1373 double max=0, priority;
1375 int eArgsNumber = e -> args.number();
1376 for (int i=0; i < eArgsNumber; i++)
1378 priority = defaultPriorityLP(e -> args[i]);
1379 if (first || (priority > max))
1387 assert(!"expression not a union or LP");
1391 return 0; // dummy for BCC
1394 eFlag Tree::parse(Sit S, DataLine *d)
1396 Log1(S, L1_PARSING, getURI());
1397 double time_was = getMillisecs();
1398 TreeConstructer tc(S);
1399 eFlag retval = tc.parseDataLineUsingExpat(S, this, d);
1402 Log1(S, L1_PARSE_DONE, getMillisecsDiff(time_was));
1407 eFlag Tree::getMatchingList(Sit S, Expression& match, Context& result)
1409 E( getRoot().getMatchingList(S, match, result) );
1413 Bool Tree::isExtensionUri(Phrase uri)
1415 return getCurrentInfo() -> getExtensionNS().findNdx(uri) != -1;
1418 eFlag Tree::insertRule(Sit S, XSLElement *tmpl)
1421 Attribute *a = tmpl -> atts.find(XSLA_PRIORITY);
1423 prio = defaultPriority(tmpl);
1426 if (a -> cont.toDouble(prio))
1427 Err(S, ET_BAD_NUMBER);
1430 GP( QName ) mode = NULL;
1431 if (!!(a = tmpl -> atts.find(XSLA_NAME)))
1432 E( tmpl -> setLogical(S, q, a -> cont, FALSE) );
1433 if (q.getLocal() != UNDEF_PHRASE &&
1434 subtrees.getCurrent() -> getStructure() -> rules().findByName(
1438 expandQStr(q, fullName);
1440 Err1(S, ET_DUPLICATE_RULE_NAME, fullName);
1442 if (!!(a = tmpl -> atts.find(XSLA_MODE)))
1443 E( tmpl -> setLogical(S, *(mode = new QName),
1444 a -> cont, FALSE) );
1446 subtrees.getCurrent() -> getStructure() -> rules().insert(
1447 new RuleItem(tmpl,prio,q,mode.keep()));
1451 eFlag Tree::insertAttSet(Sit S, XSLElement *tmpl)
1455 GP( QName ) sets = NULL;
1456 if (!!(a = tmpl -> atts.find(XSLA_NAME)))
1457 E( tmpl -> setLogical(S, q, a -> cont, FALSE) );
1458 if (q.getLocal() != UNDEF_PHRASE &&
1459 attSets().findByName(q))
1462 expandQStr(q, fullName);
1463 Err1(S, ET_DUPLICATE_ASET_NAME, fullName);
1465 attSets().append(new AttSet(q));
1471 eFlag Tree::startSubtree(Sit S, const Str& baseURI, XSL_OP dependency,
1472 Bool isInline /* = FALSE */)
1474 // look if the URI is on the way to root of the include tree
1475 if (subtrees.findAmongPredecessors(baseURI))
1476 Err1(S, E1_CIRCULAR_INCLUSION, baseURI);
1477 StylesheetStructure *structure;
1478 if (dependency == XSL_IMPORT)
1479 structure = createStylesheetStructure(S);
1481 // find structure of current subtree (always defined since Tree::Tree)
1482 structure = NZ(subtrees.getCurrent()) -> getStructure();
1491 excludeStdNamespaces();
1492 //set parent tree (closest non-inline)
1494 for (SubtreeInfo *nfo = subtrees.getCurrent();
1496 nfo = nfo -> getParentSubtree())
1498 if (!nfo -> isInline())
1500 subtrees.getCurrent() -> setMasterSubtree(nfo);
1508 eFlag Tree::endSubtree(Sit S, XSL_OP dependency)
1511 subtrees.getCurrent()->getStructure()->setImportPrecedence(importUnique);
1512 if (dependency == XSL_IMPORT)
1518 // move current subtree
1523 StylesheetStructure* Tree::createStylesheetStructure(Sit S)
1525 // current subtree is created in Tree::Tree() so must be NZ
1526 SubtreeInfo *currSubtree = NZ( subtrees.getCurrent() );
1527 // there is always a structure for an existing subtree
1528 StylesheetStructure *currStruct = NZ( currSubtree -> getStructure() );
1529 // create new structure with precedence one higher
1530 //StylesheetStructure *newStruct = new StylesheetStructure(
1531 //currStruct -> getImportPrecedence() + 1);
1532 StylesheetStructure *newStruct = new StylesheetStructure(0);
1534 // file newStruct into existing tree if stylesheet structures
1535 currStruct -> addImportStructure(S, newStruct);
1539 eFlag Tree::findBestRule(
1545 SubtreeInfo *subtree /* NULL */)
1547 SubtreeInfo *start = (importsOnly && subtree) ? subtree : subtrees[0];
1548 return NZ(start) -> getStructure() -> findBestRule(
1549 S, ret, c, currMode, importsOnly);
1552 Bool Tree::hasAnyStrippedName() {
1553 if (hasAnyStripped == -1)
1554 hasAnyStripped = subtrees[0] -> getStructure() -> hasAnyStripped();
1555 return hasAnyStripped;
1558 Bool Tree::hasAnyPreservedName() {
1559 if (hasAnyPreserved == -1)
1560 hasAnyPreserved = subtrees[0] -> getStructure() -> hasAnyPreserved();
1561 return hasAnyPreserved;
1564 Bool Tree::findStrippedName(EQName &name, int &prec, double &prio)
1567 NZ(subtrees[0]) -> getStructure() ->
1568 findStrippedName(name, prec, prio);
1571 Bool Tree::findPreservedName(EQName &name, int &prec, double &prio)
1574 NZ(subtrees[0]) -> getStructure() ->
1575 findPreservedName(name, prec, prio);
1578 XSLElement* Tree::findRuleByName(QName &q)
1580 return NZ( subtrees[0] ) -> getStructure() -> findRuleByName(*this, q);
1584 eFlag Tree::resolveGlobals(Sit S, Context *c, Processor *proc)
1588 for (int i = 0; i < toplevelVars.number(); i++)
1590 // resolve the global identified by pointer
1591 // the name does not matter
1593 E( proc -> resolveGlobal(S, c, temp, toplevelVars[i] -> getElement()) );
1599 void Tree::setUnparsedEntityUri(Str &name, Str &uri)
1601 unparsedEntities.appendConstruct(name, uri);
1604 Str* Tree::getUnparsedEntityUri(Str &name)
1606 return unparsedEntities.find(name);
1609 eFlag Tree::pushPendingNS(Sit S, Tree* srcTree, NSList &other)
1611 NSList *lst = new(&theArena) NSList();
1612 lst -> swallow(S, other, srcTree, this);
1613 pendingNSList.append(lst);
1617 eFlag Tree::popPendingNS(Sit S)
1619 pendingNSList.freelast(FALSE);
1624 void Tree::speakDebug()
1627 getRoot().speak(foo, (SpeakMode)(SM_OFFICIAL | SM_INS_SPACES));
1628 printf("--------------------\n%s\n--------------------\n", (char*)foo);
1633 /****************************************
1634 T m p L i s t methods
1635 ****************************************/
1637 TmpList::TmpList():PList<Vertex *>()
1640 puts("TmpList constructor");
1642 //printf("TmpList constructor >%x<\n",this);
1648 puts("TmpList destructor");
1653 void TmpList::append(void *what)
1655 // printf("TmpList append\n");
1656 ((Vertex *)what)->ordinal=number();
1657 PList<Vertex *>::append((Vertex *)what);
1660 void TmpList::rm(int n)
1662 // printf("TmpList rm >%d<\n",n);
1663 PList<Vertex *>::rm(n);
1664 for(int i=n;i<number();i++)
1665 (*this)[i]->ordinal=i;
1668 void TmpList::freeall(Bool a)
1671 printf("TmpList freeall(Bool)\n");
1673 PList<Vertex *>::freeall(a);
1676 void TmpList::dump(int p)
1680 if(p==0) printf("TmpList.dump (%d item(s))\n", nItems);
1681 else printf("TmpList.dump %d (%d item(s))\n", p, nItems);
1682 for(int i=0; i<nItems; i++){
1683 ((*this)[i])->getOwner().expandQStr(toE((*this)[i]) -> getName(),vname);
1684 printf("%d:>%d< >%x< (%s)\n",i,((*this)[i])->ordinal,((*this)[i]),(char*)vname);
1689 int TmpList::findNum(void *p) const
1692 for (i = number()-1; (i >= 0) && !((Vertex *)p == (*this)[i]); i--) {};
1696 void TmpList::rmP(void *p)
1698 rm(((Vertex *)p)->ordinal);
1702 Attribute* AttsCache::find(XSL_ATT what)
1707 for (i = 0; i < num; i++)
1709 // need to use a temporary variable
1710 // to get around Solaris template problem
1711 Vertex * pTemp = (*this)[i];
1712 a = cast(Attribute *, pTemp);
1713 if (a -> op == what)
1719 int AttsCache::findNdx(const QName& attName)
1724 for (i = 0; i < num; i++)
1726 // need to use a temporary variable
1727 // to get around Solaris template problem
1728 Vertex * pTemp = (*this)[i];
1730 if (attName == a -> getName())
1736 Attribute* AttsCache::find(const QName& attName)
1738 int ndx = findNdx(attName);
1739 // need to use a temporary variable
1740 // to get around Solaris template problem
1743 Vertex * pTemp = (*this)[ndx];