1 /*
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/
6 *
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.
11 *
12 * The Original Code is the Sablotron XSLT Processor.
13 *
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.
17 *
18 * Contributor(s):
19 *
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
30 * GPL.
31 */
32
33 #include "tree.h"
34 #include "proc.h"
35 #include "guard.h"
36 #include "key.h"
37
38 /* ------------------------------------------------------------ */
39 /* SpaceNameList */
40 /* -------------------------------------------------------------*/
41
findName(EQName & ename,double & prio)42 Bool SpaceNameList::findName(EQName &ename, double &prio)
43 {
44 int num = number();
45 prio = -10;
46 Bool found = 0;
47 for (int i = 0; i < num; i++)
48 {
49 EQName *aux = operator[](i);
50 if (aux -> getLocal() == (const char*) "*")
51 {
52 if (aux -> getUri() == (const char*) "")
53 {
54 found = 1;
55 prio = -0.5;
56 }
57 else
58 if (ename.getUri() == aux -> getUri())
59 {
60 found = 1;
61 prio = -0.25;
62 }
63 }
64 else
65 {
66 if (ename.getLocal() == aux -> getLocal() &&
67 ename.getUri() == aux -> getUri())
68 {
69 found = 1;
70 prio = 0;
71 break; //exit loop, we can't get better match
72 }
73 }
74 }
75 return found;
76 }
77
78 /* ------------------------------------------------------------ */
79 /* StylesheetStructure */
80 /* -------------------------------------------------------------*/
81
82 //
83 //
84 // SubtreeInfo
85 //
86 //
87
~SubtreeInfo()88 SubtreeInfo::~SubtreeInfo()
89 {
90 excludedNS.deppendall();
91 extensionNS.deppendall();
92 excludedCount.deppendall();
93 extensionCount.deppendall();
94 }
95
pushNamespaceMarks()96 void SubtreeInfo::pushNamespaceMarks()
97 {
98 excludedCount.append(excludedNS.number());
99 extensionCount.append(extensionNS.number());
100 }
101
popNamespaceMarks()102 void SubtreeInfo::popNamespaceMarks()
103 {
104 //excluded
105 int limit = excludedCount.number() ? excludedCount.last() : 0;
106 int idx;
107 for (idx = excludedNS.number() - 1; idx >= limit; idx--)
108 excludedNS.deppend();
109 if (excludedCount.number()) excludedCount.deppend();
110 //extensions
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();
115 }
116
117 //
118 //
119 // StylesheetSructure
120 //
121 //
122
findBestRule(Sit S,XSLElement * & ret,Context * c,QName * currMode,Bool importsOnly)123 eFlag StylesheetStructure::findBestRule(
124 Sit S,
125 XSLElement *&ret,
126 Context *c,
127 QName *currMode,
128 Bool importsOnly)
129 {
130 int i;
131 ret = NULL;
132 // if we don't process imports only, look at the rules in this
133 // structure
134 if (!importsOnly)
135 {
136 int rulesNumber = rulesList.number();
137 int bestRule = -1;
138 double bestPrio = 0;
139 Expression *pattern = NULL;
140 QName *thisMode;
141 XSLElement *therule;
142 for (i = 0; i < rulesNumber; i++)
143 {
144 if (
145 (bestRule != -1) &&
146 (fcomp(rulesList[i] -> priority, bestPrio) == -1)
147 // current < best
148 )
149 break;
150 therule = rulesList[i] -> rule;
151 Attribute *a = rulesList[i] -> match;
152 if (a)
153 pattern = a -> expr;
154 else
155 continue;
156
157 thisMode = rulesList[i] -> mode;
158 if ((!thisMode) ^ (!currMode))
159 continue;
160 if (thisMode && !((*thisMode) == (*currMode)))
161 continue;
162 // else both thisMode and currMode are NULL which is OK
163 if (pattern)
164 {
165 Bool result;
166 E( pattern -> matchesPattern(S, c, result) );
167 if (result)
168 {
169 bestRule = i;
170 bestPrio = rulesList[i] -> priority;
171 }
172 };
173 };
174 if (bestRule != -1)
175 ret = rulesList[bestRule] -> rule; // else remains NULL
176 }
177
178 // if no match was found, look at the imported stylesheets
179 if (!ret)
180 {
181 int importCount = importChildren.number();
182 for (i = 0; i < importCount && !ret; i++)
183 {
184 // call findBestRule recursively, setting importsOnly to FALSE
185 E( importChildren[i] -> findBestRule(
186 S, ret, c, currMode, FALSE));
187 }
188 }
189 return OK;
190 };
191
findRuleByName(Tree & t,QName & q)192 XSLElement* StylesheetStructure::findRuleByName(Tree &t, QName &q)
193 {
194 XSLElement* ret = rulesList.findByName(t,q);
195 if (! ret)
196 {
197 int importCount = importChildren.number(),
198 i;
199 for (i = 0; !ret && i < importCount; i++)
200 ret = importChildren[i] -> findRuleByName(t,q);
201 //ret = importChildren[i] -> rulesList.findByName(t,q);
202 }
203 return ret;
204 }
205
hasAnyStripped()206 Bool StylesheetStructure::hasAnyStripped()
207 {
208 Bool ret = strippedNamesList.number();
209 if (!ret)
210 {
211 int importCount = importChildren.number();
212 for (int i = 0; i < importCount && !ret; i++)
213 {
214 ret = importChildren[i] -> hasAnyStripped();
215 }
216 }
217 return ret;
218 }
219
hasAnyPreserved()220 Bool StylesheetStructure::hasAnyPreserved()
221 {
222 Bool ret = preservedNamesList.number();
223 if (!ret)
224 {
225 int importCount = importChildren.number();
226 for (int i = 0; i < importCount && !ret; i++)
227 {
228 ret = importChildren[i] -> hasAnyPreserved();
229 }
230 }
231 return ret;
232 }
233
findStrippedName(EQName & ename,int & prec,double & pri)234 Bool StylesheetStructure::findStrippedName(EQName &ename, int &prec, double &pri)
235 {
236 Bool ret = FALSE;
237 if (strippedNamesList.findName(ename, pri)) {
238 prec = importPrecedence;
239 ret = TRUE;
240 }
241 else
242 {
243 int importCount = importChildren.number();
244 for (int i = 0; i < importCount && !ret; i++)
245 {
246 // call findBestRule recursively, setting importsOnly to FALSE
247 ret = importChildren[i] -> findStrippedName(ename, prec, pri);
248 }
249 }
250 return ret;
251 }
252
findPreservedName(EQName & ename,int & prec,double & pri)253 Bool StylesheetStructure::findPreservedName(EQName &ename, int &prec, double &pri)
254 {
255 Bool ret = FALSE;
256 if (preservedNamesList.findName(ename, pri)) {
257 prec = importPrecedence;
258 ret = TRUE;
259 }
260 else
261 {
262 int importCount = importChildren.number();
263 for (int i = 0; i < importCount && !ret; i++)
264 {
265 // call findBestRule recursively, setting importsOnly to FALSE
266 ret = importChildren[i] -> findPreservedName(ename, prec, pri);
267 }
268 }
269 return ret;
270 }
271
272
273 //
274 //
275 // SubtreeList
276 //
277 //
278
279
280 //
281 //
282 // VarDirectory
283 //
284 //
285
VarDirectory()286 VarDirectory::VarDirectory()
287 {
288 }
289
~VarDirectory()290 VarDirectory::~VarDirectory()
291 {
292 freeall(FALSE);
293 }
294
find(QName & name)295 XSLElement* VarDirectory::find(QName& name)
296 {
297 int i = findNdx(name);
298 return (i == -1)? NULL : (*this)[i] -> getElement();
299 }
300
insert(Sit S,QName & name,XSLElement * var)301 eFlag VarDirectory::insert(Sit S, QName &name, XSLElement* var)
302 {
303 int i = findNdx(name);
304 if (i == -1)
305 append(new VarDirectoryItem(name, var));
306 else
307 {
308 // if precedences are equal, raise error
309 int
310 oldPrec = (*this)[i] -> getElement() -> getImportPrecedence(),
311 newPrec = var -> getImportPrecedence();
312 // due to immediate resolution of xsl:import, new must be <= old
313 sabassert(newPrec <= oldPrec);
314 (*this)[i] -> setElement(var);
315 if (newPrec == oldPrec)
316 {
317 Str fullName;
318 var -> getOwner().expandQStr(name, fullName);
319 Err1(S, E1_MULT_ASSIGNMENT, fullName);
320 }
321 }
322 return OK;
323 }
324
325
findNdx(const QName & name)326 int VarDirectory::findNdx(const QName& name)
327 {
328 int i;
329 for (i = 0; i < number(); i++)
330 {
331 if ( (*this)[i] -> getName() == name )
332 return i;
333 }
334 return -1;
335 }
336
337 /*****************************************************************
338
339 Attribute Sets
340
341 *****************************************************************/
342
343 //
344 //
345 // AttSetMember implementation
346 //
347 //
348
set(XSLElement * newAttDef)349 void AttSetMember::set(XSLElement *newAttDef)
350 {
351 int oldPrec = attDef ?
352 attDef -> getImportPrecedence() : -1;
353 int newPrec = newAttDef -> getImportPrecedence();
354 if (oldPrec == newPrec && !redefinition)
355 redefinition = newAttDef;
356 if (newPrec <= oldPrec || oldPrec == -1)
357 attDef = newAttDef;
358 if (newPrec < oldPrec)
359 redefinition = NULL;
360 }
361
362 //
363 //
364 // AttSet
365 //
366 //
367
AttSet(QName & name_)368 AttSet::AttSet(QName &name_)
369 : name(name_)
370 {
371 };
372
~AttSet()373 AttSet::~AttSet()
374 {
375 freeall(FALSE);
376 //don't free this list items, these are copies of
377 //pointers stored with xsl:attribute-set element
378 //usedSets.freeall(FALSE);
379 usedSets.deppendall();
380 }
381
checkRedefinitions(Sit S)382 eFlag AttSet::checkRedefinitions(Sit S)
383 {
384 for (int i = 0; i < number(); i++)
385 if ((*this)[i] -> getRedefinition())
386 {
387 XSLElement *redef = (*this)[i] -> getRedefinition();
388 Str fullNameAtt, fullNameThis;
389 redef -> getOwner().expandQStr((*this)[i] -> getAttName(), fullNameAtt);
390 redef -> getOwner().expandQStr(getName(), fullNameThis);
391 S.setCurrVDoc(redef);
392 Warn2(S, W2_ATTSET_REDEF, fullNameAtt, fullNameThis);
393 }
394 return OK;
395 }
396
execute(Sit S,Context * c,Tree & sheet,QNameList & history,Bool resolvingGlobals)397 eFlag AttSet::execute(Sit S, Context *c, Tree& sheet, QNameList& history, Bool resolvingGlobals)
398 {
399 if (history.findNdx(name) != -1)
400 {
401 Str fullName;
402 sheet.expandQStr(name, fullName);
403 Err1(S, E1_CIRCULAR_ASET_REF, fullName);
404 }
405 history.append(&name);
406 int i;
407 for (i = 0; i < usedSets.number(); i++)
408 E( sheet.attSets().executeAttSet(S, *(usedSets[i]), c,
409 sheet, history, resolvingGlobals) );
410 history.deppend();
411
412 for (i = 0; i < number(); i++)
413 {
414 XSLElement *def = (*this)[i] -> getAttributeDef();
415 //execute the content
416 E( def -> execute(S, c, resolvingGlobals) );
417 }
418 return OK;
419 }
420
findNdx(QName & attName)421 int AttSet::findNdx(QName &attName)
422 {
423 for (int i = 0; i < number(); i++)
424 if ((*this)[i] -> getAttName() == attName)
425 return i;
426 return -1;
427 }
428
insertAttributeDef(XSLElement * attDef,QName & attName)429 void AttSet::insertAttributeDef(XSLElement *attDef, QName &attName)
430 {
431 int ndx = findNdx(name);
432 if (ndx == -1)
433 {
434 append(new AttSetMember(attName));
435 ndx = number() - 1;
436 }
437 (*this)[ndx] -> set(attDef);
438 }
439
insertUses(QName & usedSet)440 void AttSet::insertUses(QName &usedSet)
441 {
442 if (usedSets.findNdx(usedSet) == -1)
443 usedSets.append(&usedSet);
444 }
445
446
447 //
448 //
449 // AttSetList
450 //
451 //
452
AttSetList()453 AttSetList::AttSetList()
454 :
455 PList<AttSet*>(LIST_SIZE_LARGE)
456 {};
457
~AttSetList()458 AttSetList::~AttSetList()
459 {
460 freeall(FALSE);
461 }
462
checkRedefinitions(Sit S)463 eFlag AttSetList::checkRedefinitions(Sit S)
464 {
465 for (int i = 0; i < number(); i++)
466 E( (*this)[i] -> checkRedefinitions(S) );
467 return OK;
468 }
469
insert(QName & name)470 AttSet* AttSetList::insert(QName &name)
471 {
472 int ndx = findNdx(name);
473 AttSet *ptr = NULL;
474 if (ndx == -1)
475 append(ptr = new AttSet(name));
476 else
477 ptr = (*this)[ndx];
478 return ptr;
479 }
480
executeAttSet(Sit S,QName & name,Context * c,Tree & sheet,QNameList & history,Bool resolvingGlobals)481 eFlag AttSetList::executeAttSet(Sit S, QName &name, Context *c, Tree &sheet, QNameList& history, Bool resolvingGlobals)
482 {
483 int ndx = findNdx(name);
484 if (ndx == -1)
485 {
486 Str fullName;
487 sheet.expandQStr(name, fullName);
488 Err1(S, E1_NONEX_ASET_NAME, fullName);
489 }
490 E( (*this)[ndx] -> execute(S, c, sheet, history, resolvingGlobals) );
491 return OK;
492 }
493
findNdx(const QName & what) const494 int AttSetList::findNdx(const QName &what) const
495 {
496 int count = number();
497 for (int i = 0; i < count; i++)
498 if ((*this)[i] -> getName() == what)
499 return i;
500 return -1;
501 }
502
503 //
504 //
505 // AliasItem implementation
506 //
507 //
508
set(Phrase newKey,Phrase newValue,Phrase newPrefix,int newPrecedence,XSLElement * source)509 void AliasItem::set(Phrase newKey, Phrase newValue, Phrase newPrefix,
510 int newPrecedence, XSLElement *source)
511 {
512 sabassert(newPrecedence >= 0);
513 if (key == UNDEF_PHRASE) key = newKey;
514 if (precedence == newPrecedence && value != newValue && !redefinition)
515 redefinition = source;
516 if (newPrecedence <= precedence || precedence == -1)
517 {
518 value = newValue;
519 precedence = newPrecedence;
520 prefix = newPrefix;
521 }
522 if (newPrecedence < precedence)
523 redefinition = NULL;
524 }
525
526 //
527 //
528 // AliasList implementation
529 //
530 //
531
findNdx(Phrase key_) const532 int AliasList::findNdx(Phrase key_) const
533 {
534 int i, count = number();
535 for (i = 0; (i < count) && !(key_ == ((*this)[i] -> getKey())); i++);
536 return (i < count) ? i : -1;
537 }
538
find(Phrase key_) const539 Phrase AliasList::find(Phrase key_) const
540 {
541 int ndx = findNdx(key_);
542 return (ndx != -1) ? (*this)[ndx] -> getValue() : PHRASE_NOT_FOUND;
543 }
544
insertAlias(Phrase key,Phrase value,Phrase prefix,int precedence,XSLElement * source)545 void AliasList::insertAlias(Phrase key, Phrase value, Phrase prefix,
546 int precedence, XSLElement *source)
547 {
548 AliasItem *newItem;
549 int ndx = findNdx(key);
550 if (ndx == -1)
551 append(newItem = new AliasItem);
552 else
553 newItem = (*this)[ndx];
554 newItem -> set(key, value, prefix, precedence, source);
555 }
556
checkRedefinitions(Sit S,Tree & sheet)557 eFlag AliasList::checkRedefinitions(Sit S, Tree &sheet)
558 {
559 for (int i = 0; i < number(); i++)
560 if ((*this)[i] -> getRedefinition())
561 {
562 S.setCurrVDoc((*this)[i] -> getRedefinition());
563 Str fullName;
564 sheet.expand((*this)[i] -> getKey());
565 Warn1(S, W1_ALIAS_REDEF, fullName);
566 }
567 return OK;
568 }
569
570 /****************************************
571 T r e e methods
572 ****************************************/
573
Tree(const Str & aname,BOOL aXSLTree)574 Tree::Tree(const Str &aname, BOOL aXSLTree)
575 : theArena(TREE_ARENA_SIZE), theDictionary(&theArena, TREE_DICT_LOGSIZE),
576 structure(0)
577 {
578 // theDictionary.initialize();
579 QName &rootname = (QName&) getTheEmptyQName();
580 root = new(&theArena) RootNode(*this, rootname);
581 XSLTree = aXSLTree;
582 stackTop = &getRoot();
583 pendingTextNode = NULL;
584 getRoot().stamp = 0;
585 vcount = 1;
586 QName dummyName;
587 theDummyElement = new(&theArena) Element(*this, dummyName);
588 initDict();
589
590 // append entry for 'the whole tree' to subtrees
591 subtrees.push(new SubtreeInfo(
592 aname, XSL_NONE, &structure, FALSE));
593 getRoot().setSubtreeInfo(subtrees.last());
594
595 excludeStdNamespaces();
596
597 pendingNSList.append(new(&theArena) NSList());
598
599 stripped = aXSLTree;
600 hasAnyStripped = hasAnyPreserved = -1;// means 'who knows?'
601 importUnique = 0xFFFF;
602 };
603
~Tree()604 Tree::~Tree()
605 {
606 getRoot().~RootNode();
607 // this is just in case there's a processing error:
608 //pendingNSList.freeall(FALSE);
609 delete theDummyElement;
610 // clear subtree information
611 subtrees.freeall(FALSE);
612 aliasesList.freeall(FALSE);
613 unparsedEntities.freeall(FALSE);
614
615 pendingNSList.freelast(FALSE);
616 //sabassert(!pendingNSList.number());
617 //tmpList must be empty before the arena gets down automatically
618 tmpList.freeall(FALSE);
619 }
620
initDict()621 void Tree::initDict()
622 {
623 theDictionary.initialize();
624 theDictionary.insert("", stdPhrases[PHRASE_EMPTY]);
625 theDictionary.insert("xsl", stdPhrases[PHRASE_XSL]);
626 theDictionary.insert(theXSLTNamespace, stdPhrases[PHRASE_XSL_NAMESPACE]);
627 theDictionary.insert(theXMLNamespace, stdPhrases[PHRASE_XML_NAMESPACE]);
628 theDictionary.insert(theSabExtNamespace, stdPhrases[PHRASE_SABEXT_NAMESPACE]);
629 theDictionary.insert("*", stdPhrases[PHRASE_STAR]);
630 theDictionary.insert("xmlns", stdPhrases[PHRASE_XMLNS]);
631 theDictionary.insert("lang", stdPhrases[PHRASE_LANG]);
632 }
633
excludeStdNamespaces()634 void Tree::excludeStdNamespaces()
635 {
636 NZ(getCurrentInfo()) ->
637 getExcludedNS().addUri(stdPhrase(PHRASE_XML_NAMESPACE));
638 if (XSLTree)
639 {
640 NZ(getCurrentInfo()) ->
641 getExcludedNS().addUri(stdPhrase(PHRASE_XSL_NAMESPACE));
642 }
643 }
644
dummyElement() const645 Element &Tree::dummyElement() const
646 {
647 return *theDummyElement;
648 }
649
flushPendingText()650 void Tree::flushPendingText()
651 {
652 if (pendingTextNode)
653 pendingTextNode -> cont = pendingText;
654 pendingText.empty();
655 pendingTextNode = NULL;
656 }
657
appendVertex(Sit S,Vertex * v)658 eFlag Tree::appendVertex(Sit S, Vertex *v)
659 {
660 sabassert(stackTop && isDaddy(stackTop));
661 sabassert(!isText(v) || !pendingTextNode);
662 if (!isText(v))
663 flushPendingText();
664 E( cast(Daddy*,stackTop) -> newChild(S, v) ); //sets parent too
665 if (isDaddy(v))
666 stackTop = v;
667 v -> stamp = vcount++;
668 // set the subtree information for vertex
669 v -> setSubtreeInfo(subtrees.getCurrent());
670 return OK;
671 };
672
dropCurrentElement(Vertex * v)673 void Tree::dropCurrentElement(Vertex *v)
674 {
675 sabassert(stackTop && isElement(stackTop));
676 sabassert(stackTop == v);
677 sabassert(!pendingTextNode);
678 stackTop = v -> parent;
679 delete v;
680 toE(stackTop) -> contents.deppend();
681 }
682
appendText(Sit S,char * string,int len)683 Vertex* Tree::appendText(Sit S, char *string, int len)
684 {
685 Vertex *txt = NULL;
686 if (!pendingTextNode)
687 {
688 // the initializing text does not matter
689 txt = new(&getArena()) Text(*this, string, len);
690 Processor *proc = S.getProcessor();
691 if ( proc && proc->outputter() )
692 {
693 OutputDocument *doc=proc->outputter()->getDocumentForLevel(FALSE);
694 txt -> setOutputDocument(doc);
695 }
696
697 appendVertex(S, txt);
698 pendingTextNode = toText(txt);
699 }
700 pendingText.nadd(string,len);
701 return txt;
702 }
703
popVertex()704 Vertex* Tree::popVertex()
705 {
706 Vertex *v = NZ( stackTop );
707 stackTop = v -> parent;
708 return v;
709 }
710
parseFinished(Sit S)711 eFlag Tree::parseFinished(Sit S)
712 {
713 flushPendingText();
714 return OK;
715 }
716
dict()717 HashTable& Tree::dict()
718 {
719 return theDictionary;
720 }
721
getArena()722 SabArena& Tree::getArena()
723 {
724 return theArena;
725 }
726
getTheEmptyQName() const727 const QName& Tree::getTheEmptyQName() const
728 {
729 return theEmptyQName;
730 }
731
732
cmpQNames(const QName & first,const QName & second) const733 Bool Tree::cmpQNames(const QName &first, const QName &second) const
734 {
735 /*
736 printf("comparing names (%s,%s,%s) and (%s,%s,%s)\n",
737 (char*)(((Tree*)this)->expand(first.getPrefix())),
738 (char*)(((Tree*)this)->expand(first.getUri())),
739 (char*)(((Tree*)this)->expand(first.getLocal())),
740 (char*)(((Tree*)this)->expand(second.getPrefix())),
741 (char*)(((Tree*)this)->expand(second.getUri())),
742 (char*)(((Tree*)this)->expand(second.getLocal()))
743 );
744 */
745 if (first.getLocal() == stdPhrase(PHRASE_STAR))
746 return (Bool)(first.getPrefix() == UNDEF_PHRASE ||
747 first.getUri() == second.getUri());
748 else
749 return (Bool) (first.getUri() == second.getUri()
750 && first.getLocal() == second.getLocal());
751 }
752
cmpQNamesForeign(const QName & q,const HashTable & dictForeign,const QName & qForeign)753 Bool Tree::cmpQNamesForeign(const QName &q, const HashTable& dictForeign, const QName &qForeign)
754 {
755 /*
756 printf("comparing names (%s,%s,%s) and (%s,%s,%s)\n",
757 (char*)(((Tree*)this)->expand(q.getPrefix())),
758 (char*)(((Tree*)this)->expand(q.getUri())),
759 (char*)(((Tree*)this)->expand(q.getLocal())),
760 (char*)(dictForeign.getKey(qForeign.getPrefix())),
761 (char*)(dictForeign.getKey(qForeign.getUri())),
762 (char*)(dictForeign.getKey(qForeign.getLocal()))
763 );
764 */
765
766 if (q.getLocal() == stdPhrase(PHRASE_STAR))
767 {
768 return (Bool)(q.getPrefix() == UNDEF_PHRASE ||
769 (dict().getKey(q.getUri()) == dictForeign.getKey(qForeign.getUri())));
770 }
771 else
772 {
773 return (Bool)
774 (dict().getKey(q.getUri()) == dictForeign.getKey(qForeign.getUri()) &&
775 dict().getKey(q.getLocal()) == dictForeign.getKey(qForeign.getLocal()));
776 }
777 }
778
cmpQNameStrings(const QName & q,const Str & uri,const Str & local)779 Bool Tree::cmpQNameStrings(const QName &q, const Str& uri, const Str& local)
780 {
781 if (q.getLocal() == stdPhrase(PHRASE_STAR))
782 return (Bool)(
783 q.getUri() == UNDEF_PHRASE || dict().getKey(q.getUri()) == uri);
784 else
785 {
786 return (Bool)
787 (dict().getKey(q.getUri()) == uri &&
788 dict().getKey(q.getLocal()) == local);
789 }
790 }
791
expandQ(const QName & q,EQName & expanded)792 void Tree::expandQ(const QName& q, EQName& expanded)
793 {
794 expanded.setLocal(expand(q.getLocal()));
795 expanded.setUri(expand(q.getUri()));
796 expanded.setPrefix(expand(q.getPrefix()));
797 }
798
expandQStr(const QName & q,Str & expName)799 void Tree::expandQStr(const QName& q, Str& expName)
800 {
801 EQName expanded;
802 expandQ(q, expanded);
803 expanded.getname(expName);
804 }
805
expand(Phrase ph)806 const Str& Tree::expand(Phrase ph)
807 {
808 return dict().getKey(ph);
809 }
810
unexpand(const Str & strg)811 Phrase Tree::unexpand(const Str& strg)
812 {
813 Phrase result;
814 dict().insert(strg, result);
815 return result;
816 }
817
serialize(Sit S,char * & result)818 eFlag Tree::serialize(Sit S, char *& result)
819 {
820 OutputterObj out;
821 OutputDefinition def;
822 GP( DataLine ) targetLine = new DataLine;
823 // set default options for output
824 EQName xmlMethod;
825 xmlMethod.setLocal((char*)"xml");
826 E( def.setItemEQName(S, XSLA_METHOD, xmlMethod, NULL, OUTPUT_PRECEDENCE_WEAKEST) );
827 E( def.setDefaults(S) );
828 E( (*targetLine).open(S, (const char*)"arg:/dummy_", DLMODE_WRITE, NULL) );
829 out.setOptions(S, targetLine, &def);
830 E( getRoot().serialize(S, out) );
831 result = (*targetLine).getOutBuffer() -> compactToBuffer();
832 E( (*targetLine).close(S) );
833 targetLine.del();
834 return OK;
835 }
836
serializeNode(Sit S,Element * v,char * & result)837 eFlag Tree::serializeNode(Sit S, Element *v, char *& result)
838 {
839 OutputterObj out;
840 OutputDefinition def;
841 GP( DataLine ) targetLine = new DataLine;
842 // set default options for output
843 EQName xmlMethod;
844 xmlMethod.setLocal((char*)"xml");
845 E( def.setItemEQName(S, XSLA_METHOD, xmlMethod, NULL, OUTPUT_PRECEDENCE_WEAKEST) );
846 E( def.setDefaults(S) );
847 E( (*targetLine).open(S, (const char*)"arg:/dummy_", DLMODE_WRITE, NULL) );
848 out.setOptions(S, targetLine, &def);
849 E( (*v).serializeSubtree(S, out) );
850 result = (*targetLine).getOutBuffer() -> compactToBuffer();
851 E( (*targetLine).close(S) );
852 targetLine.del();
853 return OK;
854 }
855
makeStamps()856 void Tree::makeStamps()
857 {
858 int stamp_ = 0;
859 getRoot().makeStamps(stamp_);
860 vcount = stamp_;
861 }
862
updateImportStatus()863 void Tree::updateImportStatus()
864 {
865 if (! subtrees.getCurrent() -> getStructure() -> getTopLevelFound() )
866 {
867 StylesheetStructure * stru = subtrees.getCurrent() -> getStructure();
868 stru -> setTopLevelFound(true);
869 stru -> setImportPrecedence(importUnique);
870 importUnique--;
871 }
872 }
873
874 /*****************************************************************
875 Tree::processVertexAfterParse()
876 Performs any necessary actions on a vertex immediately after it is
877 parsed into the tree. The vertex is still 'current'. Typically, this
878 function calls popVertex.
879 ARGS:
880 v the vertex to be processed
881 The function operates only on XSL vertices, namely:
882 xsl:include - replaces the vertex by the newly constructed tree
883 xsl:output - files the information into the tree's structures
884 ...
885 Other vertices are just popped off the stack.
886 *****************************************************************/
887
processVertexAfterParse(Sit S,Vertex * v,TreeConstructer * tc)888 eFlag Tree::processVertexAfterParse(Sit S, Vertex *v, TreeConstructer* tc)
889 {
890 //be careful with this test, it might be moved deeper inside this
891 //function if needed
892
893 if (v -> vt & VT_TOP_FOREIGN)
894 {
895 popVertex();
896 return OK;
897 }
898
899 XSL_OP theOp;
900 if (isXSLElement(v))
901 {
902 XSLElement *x = toX(v);
903 theOp = x -> op;
904
905 if (theOp != XSL_IMPORT) updateImportStatus();
906
907 switch(theOp)
908 {
909 //catch xsl:use-attribute-sets
910 case XSL_ELEMENT:
911 case XSL_COPY:
912 {
913 E( extractUsedSets(S, toE(v)) );
914 popVertex();
915 }; break;
916 case XSL_IMPORT:
917 {
918 if (subtrees.getCurrent() -> getStructure() -> getTopLevelFound())
919 {
920 Err2(S, E_ELEM_CONTAINS_ELEM,
921 xslOpNames[XSL_STYLESHEET],
922 xslOpNames[XSL_IMPORT]);
923 }
924 }; // no break
925 case XSL_INCLUDE:
926 {
927 Attribute *a = NZ( x -> atts.find(XSLA_HREF) );
928 GP( Tree ) srcTree;
929 const Str& base = S.findBaseURI(a -> getSubtreeInfo() ->
930 getBaseURI());
931
932 Str absolute;
933 makeAbsoluteURI(S, a -> cont, base, absolute);
934 if (S.getProcessor())
935 {
936 E( S.getProcessor() -> readTreeFromURI(S, srcTree,
937 a -> cont, base,
938 FALSE) );
939 srcTree.keep();
940 }
941 else
942 {
943 //Str absolute;
944 //makeAbsoluteURI(a -> cont, base, absolute);
945 srcTree = new Tree(absolute, FALSE);
946 DataLine d;
947 E( d.open(S, absolute, DLMODE_READ, /* argList = */ NULL) );
948 E( (*srcTree).parse(S, &d) );
949 E( d.close(S) );
950 }
951
952 Element *theSheet=(*srcTree).findStylesheet((*srcTree).getRoot());
953 if (!theSheet)
954 Warn1(S, W_NO_STYLESHEET, (char*)(a -> cont));
955 dropCurrentElement(v);
956 if (!theSheet) // to prevent segfault after include/import failure
957 break;
958
959 OutputterObj source;
960 //we start a subtree to record where the nodes come from
961 //when including, we use the old structure
962 //when importing, Tree creates a new one
963 E( startSubtree(S, (*srcTree).getURI(), theOp) );
964 //set extension namespaces for subtree
965
966 //(*srcTree).speakDebug();
967
968 //merge it into the current tree
969 E( tc -> parseUsingSAXForAWhile(S, source, absolute,
970 TRUE,
971 (Tree*)srcTree,
972 theSheet -> namespaces) );
973
974 //first we have to deal with ext. and excl. namespaces
975 Attribute *attr;
976 QName q;
977 //exclusions
978 q.setLocal((*srcTree).unexpand("exclude-result-prefixes"));
979 attr = theSheet->atts.find(q);
980 if (attr)
981 E(pushNamespacePrefixes(S, attr->cont, XSLA_EXCL_RES_PREFIXES));
982 //extensions
983 q.setLocal((*srcTree).unexpand("extension-element-prefixes"));
984 attr = theSheet->atts.find(q);
985 if (attr)
986 E(pushNamespacePrefixes(S, attr->cont, XSLA_EXT_ELEM_PREFIXES));
987
988 if (theSheet)
989 E( theSheet -> contents.copy(S, source) );
990 E( tc -> parseUsingSAXForAWhileDone(S, source, TRUE) );
991 // end the subtree
992 E( endSubtree(S, theOp) );
993 }; break;
994 case XSL_OUTPUT:
995 {
996 int i, attsNumber = x -> atts.number();
997 Attribute *theAtt;
998 for (i = 0; i < attsNumber; i++)
999 {
1000 theAtt = toA(x -> atts[i]);
1001 switch(theAtt -> op)
1002 {
1003 case XSLA_METHOD:
1004 {
1005 QName q;
1006 EQName eq;
1007 E( x -> setLogical(S,
1008 q, theAtt -> cont, FALSE) );
1009 expandQ(q, eq);
1010 E( outputDef.setItemEQName(S, XSLA_METHOD,
1011 eq, v,
1012 v -> getImportPrecedence()) );
1013 }; break;
1014 case XSLA_CDATA_SECT_ELEMS:
1015 {
1016 QName q;
1017 Bool someRemains;
1018 Str listPart;
1019 char *p = theAtt -> cont;
1020 do
1021 {
1022 someRemains = getWhDelimString(p, listPart);
1023 if (someRemains)
1024 {
1025 E( x -> setLogical(S,
1026 q, listPart, TRUE) );
1027 EQName expanded;
1028 expandQ(q, expanded);
1029 E( outputDef.setItemEQName(S,
1030 XSLA_CDATA_SECT_ELEMS,
1031 expanded, v,
1032 v -> getImportPrecedence()) );
1033 };
1034 }
1035 while (someRemains);
1036 }; break;
1037 case XSLA_NONE: //skip other namespaces
1038 break;
1039 default:
1040 {
1041 E( outputDef.setItemStr(S, theAtt -> op, theAtt -> cont,
1042 theAtt,
1043 theAtt -> getImportPrecedence()) );
1044
1045 };
1046 };
1047 }
1048 popVertex();
1049 }; break;
1050 case XSL_NAMESPACE_ALIAS:
1051 {
1052 Phrase style, result, sUri, rUri;
1053 Attribute *sp = NZ( x -> atts.find(XSLA_STYLESHEET_PREFIX) );
1054 Attribute *rp = NZ( x -> atts.find(XSLA_RESULT_PREFIX) );
1055 if (sp -> cont == "#default") style = UNDEF_PHRASE;
1056 else dict().insert(sp -> cont, style);
1057 if (rp -> cont == "#default") result = UNDEF_PHRASE;
1058 else dict().insert(rp -> cont, result);
1059
1060 int i;
1061 i = pendingNS().findNdx(style);
1062 if (i != -1)
1063 sUri = toNS(pendingNS().operator[](i)) -> uri;
1064 else
1065 Err1(S, E_EX_NAMESPACE_UNKNOWN, (char*) sp -> cont);
1066
1067 i = pendingNS().findNdx(result);
1068 if (i != -1)
1069 rUri = toNS(pendingNS().operator[](i)) -> uri;
1070 else
1071 Err1(S, E_EX_NAMESPACE_UNKNOWN, (char*) rp -> cont);
1072
1073 aliases().insertAlias(sUri, rUri, result,
1074 v -> getImportPrecedence(), x);
1075 popVertex();
1076 }; break;
1077 case XSL_TEMPLATE:
1078 {
1079 E( insertRule(S, x) );
1080 popVertex();
1081 }; break;
1082 case XSL_ATTRIBUTE_SET:
1083 {
1084 QName name;
1085
1086 E( x -> setLogical(S, name,
1087 NZ( x -> atts.find(XSLA_NAME)) -> cont,
1088 FALSE) );
1089 AttSet *ptr = attSets().insert(name);
1090 E( extractUsedSets(S, toE(v)) );
1091 if (x -> attSetNames(FALSE))
1092 {
1093 for (int i = 0; i < x -> attSetNames(FALSE) -> number(); i++)
1094 ptr -> insertUses(*(x -> attSetNames(FALSE) -> operator[] (i)));
1095 }
1096 XSLElement *son;
1097 for (int i = 0; i < x -> contents.number(); i++)
1098 {
1099 sabassert(isXSLElement(x -> contents[i]) &&
1100 toX(x -> contents[i]) -> op == XSL_ATTRIBUTE);
1101 son = toX(x -> contents[i]);
1102 E( son -> setLogical(S, name,
1103 NZ( son -> atts.find(XSLA_NAME)) -> cont,
1104 FALSE) );
1105 ptr -> insertAttributeDef(son, name);
1106 }
1107 popVertex();
1108 }; break;
1109 case XSL_STYLESHEET:
1110 case XSL_TRANSFORM:
1111 {
1112 popVertex();
1113 }; break;
1114 case XSL_VARIABLE:
1115 case XSL_PARAM:
1116 {
1117 // only look at top-levels
1118 Vertex *par = v -> parent;
1119 if (par && isXSLElement(par) &&
1120 (toX(par) -> op == XSL_STYLESHEET ||
1121 toX(par) -> op == XSL_TRANSFORM))
1122 {
1123 // is top-level -> insert into directory,
1124 //with error if there already is an entry
1125 // with the same import precedence
1126 // find name first
1127 QName name;
1128 E( x -> setLogical(S, name,
1129 NZ( x -> atts.find(XSLA_NAME)) -> cont,
1130 FALSE) );
1131 E( toplevelVars.insert(S, name, x) );
1132 }
1133 popVertex();
1134 }; break;
1135 case XSL_STRIP_SPACE:
1136 {
1137 SpaceNameList &foo =
1138 subtrees.getCurrent() -> getStructure() -> strippedNames();
1139 E( getSpaceNames(S, *x, NZ(x -> atts.find(XSLA_ELEMENTS)) -> cont,
1140 foo) );
1141 popVertex();
1142 }; break;
1143 case XSL_PRESERVE_SPACE:
1144 {
1145 SpaceNameList &foo =
1146 subtrees.getCurrent() -> getStructure() -> preservedNames();
1147 E( getSpaceNames(S, *x, NZ(x -> atts.find(XSLA_ELEMENTS)) -> cont,
1148 foo) );
1149 popVertex();
1150 }; break;
1151 default:
1152 popVertex();
1153 }
1154 //the literal output element may have some xsl features
1155 }
1156 else
1157 { //isXSLElement
1158 updateImportStatus();
1159 if (XSLTree) {
1160 E( extractUsedSets(S, toE(v)) );
1161 popVertex();
1162 }
1163 else {
1164 popVertex();
1165 }
1166 }
1167 return OK;
1168 }
1169
getSpaceNames(Sit S,Element & e,Str & str,SpaceNameList & where)1170 eFlag Tree::getSpaceNames(Sit S, Element &e, Str &str, SpaceNameList &where)
1171 {
1172 char *p, *q;
1173 q = (char*)str;
1174 skipWhite(q);
1175 p = q;
1176 int i = strcspn(q, theWhitespace);
1177 while (*q && i)
1178 {
1179 q += i;
1180 char save = *q;
1181 *q = 0;
1182
1183 Str token = p;
1184 QName name;
1185 E( e.setLogical(S, name, token, FALSE) );
1186 GP(EQName) ename = new EQName;
1187 expandQ(name, *ename);
1188 where.append(ename.keep());
1189
1190 *q = save;
1191 skipWhite(q);
1192 p = q;
1193 i = strcspn(q, theWhitespace);
1194 }
1195
1196 return OK;
1197 }
1198
markNamespacePrefixes(Sit S)1199 eFlag Tree::markNamespacePrefixes(Sit S)
1200 {
1201 if (XSLTree)
1202 getCurrentInfo() -> pushNamespaceMarks();
1203 return OK;
1204 }
1205
pushNamespacePrefixes(Sit S,Str & prefixes,XSL_ATT att)1206 eFlag Tree::pushNamespacePrefixes(Sit S, Str& prefixes, XSL_ATT att)
1207 {
1208 if (!XSLTree) return OK;
1209
1210 PList<Str*> tokens;
1211 char *p, *q;
1212 q = (char*) prefixes;
1213 skipWhite(q);
1214 p = q;
1215 int i = strcspn(q, theWhitespace);
1216 while (*q && i)
1217 {
1218 q += i;
1219 char save = *q;
1220 *q = 0;
1221
1222 Str* aux = new Str(p);
1223 tokens.append(aux);
1224
1225 *q = save;
1226 skipWhite(q);
1227 p = q;
1228 i = strcspn(q, theWhitespace);
1229 }
1230 //add to list
1231 SubtreeInfo *info = getCurrentInfo();
1232 for (i = 0; i < tokens.number(); i++)
1233 {
1234 Str tok = *(tokens[i]);
1235 Phrase prefix =
1236 tok == (const char*) "#default" ? UNDEF_PHRASE : unexpand(tok);
1237 int idx = pendingNS().findNdx(prefix);
1238 if (idx != -1)
1239 {
1240 switch (att) {
1241 case XSLA_EXT_ELEM_PREFIXES:
1242 {
1243 info -> getExtensionNS().append(toNS(pendingNS()[idx]) -> uri);
1244 }; //no break
1245 case XSLA_EXCL_RES_PREFIXES:
1246 {
1247 info -> getExcludedNS().append(toNS(pendingNS()[idx]) -> uri);
1248 }; break;
1249 }
1250 }
1251 else
1252 {
1253 Str aux = *(tokens[i]);
1254 tokens.freeall(FALSE);
1255 Err1(S, E_EX_NAMESPACE_UNKNOWN, (char*) aux);
1256 }
1257 }
1258 tokens.freeall(FALSE);
1259 //printf("----------------------------\n");
1260 return OK;
1261 }
1262
popNamespacePrefixes(Sit S)1263 eFlag Tree::popNamespacePrefixes(Sit S)
1264 {
1265 if (XSLTree)
1266 getCurrentInfo() -> popNamespaceMarks();
1267 return OK;
1268 }
1269
extractUsedSets(Sit S,Element * e)1270 eFlag Tree::extractUsedSets(Sit S, Element *e)
1271 {
1272 Attribute *a = e -> atts.find(XSLA_USE_ATTR_SETS);
1273 if (a)
1274 {
1275 QNameList *names = e -> attSetNames(TRUE);
1276 names -> freeall(FALSE);
1277 char *p, *q;
1278
1279 q = (char*) (a -> cont);
1280 skipWhite(q);
1281 p = q;
1282 int i = strcspn(q, theWhitespace);
1283 while (*q && i) {
1284 q += i;
1285 char save = *q;
1286 *q = 0;
1287
1288 Str token = p;
1289 GP( QName ) name = new QName;
1290 E( e -> setLogical(S, *name, token, FALSE) );
1291
1292 names -> append( name.keep() );
1293 *q = save;
1294 skipWhite(q);
1295 p = q;
1296 i = strcspn(q, theWhitespace);
1297 }
1298
1299 }
1300 return OK;
1301 }
1302
1303 /*****************************************************************
1304 findStylesheet()
1305 finds a xsl:stylesheet child of the given daddy. Returns NULL
1306 if not found.
1307 *****************************************************************/
1308
findStylesheet(Daddy & d)1309 Element* Tree::findStylesheet(Daddy& d)
1310 {
1311 Vertex *w;
1312 int dContentsNumber = d.contents.number();
1313 for (int i = 0; i < dContentsNumber; i++)
1314 {
1315 if (isElement(w = d.contents[i]))
1316 {
1317 const QName& wName = toE(w) -> name;
1318 Tree& owner = w -> getOwner();
1319 Str localStr;
1320 // if (!strcmp(wName.getUri(), theXSLTNamespace) && /* _PH_ */
1321 if (wName.getUri() == owner.stdPhrase(PHRASE_XSL_NAMESPACE) &&
1322 ((localStr = owner.expand(wName.getLocal()) ==
1323 xslOpNames[XSL_STYLESHEET]) ||
1324 (localStr == xslOpNames[XSL_TRANSFORM])))
1325 return toE(w);
1326 }
1327 };
1328 return NULL;
1329 }
1330
defaultPriorityLP(Expression * lpath)1331 double Tree::defaultPriorityLP(Expression *lpath)
1332 {
1333 sabassert(lpath && lpath -> functor == EXF_LOCPATH);
1334 sabassert(lpath -> args.number());
1335 if ((lpath -> args.number() > 1) || lpath -> args[0] -> step -> preds.number())
1336 return .5;
1337 else
1338 {
1339 switch (lpath -> args[0] -> step -> ntype)
1340 {
1341 case EXNODE_COMMENT:
1342 case EXNODE_TEXT:
1343 case EXNODE_NODE:
1344 return -0.5;
1345 break;
1346 case EXNODE_PI:
1347 return lpath->args[0]->step->piname == "" ? -0.5 : 0;
1348 case EXNODE_NONE:
1349 {
1350 QName &qn = lpath -> args[0] -> step -> ntest;
1351 if (qn.getLocal() != lpath -> getOwnerTree().stdPhrase(PHRASE_STAR))
1352 return 0.0;
1353 else
1354 {
1355 if (qn.getPrefix() == UNDEF_PHRASE)
1356 return -0.5;
1357 else
1358 return -0.25;
1359 };
1360 }; break;
1361 default:
1362 return 0.5;
1363 };
1364 };
1365 return 0; // BCC thinks we don't return enough
1366 }
1367
defaultPriority(XSLElement * tmpl)1368 double Tree::defaultPriority(XSLElement *tmpl)
1369 {
1370 Expression *e = tmpl -> getAttExpr(XSLA_MATCH);
1371 if (!e)
1372 return PRIORITY_NOMATCH;
1373 switch(e -> functor)
1374 {
1375 case EXF_LOCPATH:
1376 {
1377 return defaultPriorityLP(e);
1378 }; break;
1379 case EXFO_UNION:
1380 {
1381 double max=0, priority;
1382 BOOL first = TRUE;
1383 int eArgsNumber = e -> args.number();
1384 for (int i=0; i < eArgsNumber; i++)
1385 {
1386 priority = defaultPriorityLP(e -> args[i]);
1387 if (first || (priority > max))
1388 max = priority;
1389 first = FALSE;
1390 };
1391 return max;
1392 }; break;
1393 default:
1394 {
1395 sabassert(!"expression not a union or LP");
1396 return 0; // dummy
1397 }
1398 };
1399 return 0; // dummy for BCC
1400 }
1401
parse(Sit S,DataLine * d)1402 eFlag Tree::parse(Sit S, DataLine *d)
1403 {
1404 Log1(S, L1_PARSING, getURI());
1405 double time_was = getMillisecs();
1406 TreeConstructer tc(S);
1407 eFlag retval = tc.parseDataLineUsingExpat(S, this, d);
1408 if (!retval)
1409 {
1410 Log1(S, L1_PARSE_DONE, getMillisecsDiff(time_was));
1411 }
1412 return retval;
1413 }
1414
getMatchingList(Sit S,Expression & match,Context & result)1415 eFlag Tree::getMatchingList(Sit S, Expression& match, Context& result)
1416 {
1417 E( getRoot().getMatchingList(S, match, result) );
1418 return OK;
1419 }
1420
isExtensionUri(Phrase uri)1421 Bool Tree::isExtensionUri(Phrase uri)
1422 {
1423 return getCurrentInfo() -> getExtensionNS().findNdx(uri) != -1;
1424 }
1425
insertRule(Sit S,XSLElement * tmpl)1426 eFlag Tree::insertRule(Sit S, XSLElement *tmpl)
1427 {
1428 double prio;
1429 Attribute *a = tmpl -> atts.find(XSLA_PRIORITY);
1430 if (!a)
1431 prio = defaultPriority(tmpl);
1432 else
1433 {
1434 if (a -> cont.toDouble(prio))
1435 Err(S, ET_BAD_NUMBER);
1436 };
1437 QName q;
1438 GP( QName ) mode = NULL;
1439
1440 if (!!(a = tmpl -> atts.find(XSLA_NAME)))
1441 E( tmpl -> setLogical(S, q, a -> cont, FALSE) );
1442
1443 if (q.getLocal() != UNDEF_PHRASE &&
1444 subtrees.getCurrent() -> getStructure() ->
1445 rules().findByName(*this, q))
1446 {
1447 Str fullName;
1448 expandQStr(q, fullName);
1449
1450 Err1(S, ET_DUPLICATE_RULE_NAME, fullName);
1451 };
1452
1453 if (!!(a = tmpl -> atts.find(XSLA_MODE)))
1454 E( tmpl -> setLogical(S, *(mode = new QName),
1455 a -> cont, FALSE) );
1456
1457 subtrees.getCurrent() -> getStructure() ->
1458 rules().insert(new RuleItem(tmpl,prio,q,mode.keep()));
1459 return OK;
1460 }
1461
insertAttSet(Sit S,XSLElement * tmpl)1462 eFlag Tree::insertAttSet(Sit S, XSLElement *tmpl)
1463 {
1464 QName q;
1465 Attribute *a;
1466 GP( QName ) sets = NULL;
1467 if (!!(a = tmpl -> atts.find(XSLA_NAME)))
1468 E( tmpl -> setLogical(S, q, a -> cont, FALSE) );
1469 if (q.getLocal() != UNDEF_PHRASE &&
1470 attSets().findByName(q))
1471 {
1472 Str fullName;
1473 expandQStr(q, fullName);
1474 Err1(S, ET_DUPLICATE_ASET_NAME, fullName);
1475 };
1476 attSets().append(new AttSet(q));
1477 return OK;
1478 }
1479
1480
1481
startSubtree(Sit S,const Str & baseURI,XSL_OP dependency,Bool isInline)1482 eFlag Tree::startSubtree(Sit S, const Str& baseURI, XSL_OP dependency,
1483 Bool isInline /* = FALSE */)
1484 {
1485 // look if the URI is on the way to root of the include tree
1486 if (subtrees.findAmongPredecessors(baseURI))
1487 Err1(S, E1_CIRCULAR_INCLUSION, baseURI);
1488 StylesheetStructure *structure;
1489 if (dependency == XSL_IMPORT)
1490 structure = createStylesheetStructure(S);
1491 else
1492 // find structure of current subtree (always defined since Tree::Tree)
1493 structure = NZ(subtrees.getCurrent()) -> getStructure();
1494
1495 subtrees.push(
1496 new SubtreeInfo(
1497 baseURI,
1498 dependency,
1499 structure,
1500 isInline));
1501
1502 excludeStdNamespaces();
1503 //set parent tree (closest non-inline)
1504 if (isInline)
1505 for (SubtreeInfo *nfo = subtrees.getCurrent();
1506 nfo;
1507 nfo = nfo -> getParentSubtree())
1508 {
1509 if (!nfo -> isInline())
1510 {
1511 subtrees.getCurrent() -> setMasterSubtree(nfo);
1512 break;
1513 }
1514 }
1515
1516 return OK;
1517 }
1518
endSubtree(Sit S,XSL_OP dependency)1519 eFlag Tree::endSubtree(Sit S, XSL_OP dependency)
1520 {
1521 /*
1522 subtrees.getCurrent()->getStructure()->setImportPrecedence(importUnique);
1523 if (dependency == XSL_IMPORT)
1524 {
1525 importUnique--;
1526 }
1527 */
1528
1529 // move current subtree
1530 subtrees.pop();
1531 return OK;
1532 }
1533
createStylesheetStructure(Sit S)1534 StylesheetStructure* Tree::createStylesheetStructure(Sit S)
1535 {
1536 // current subtree is created in Tree::Tree() so must be NZ
1537 SubtreeInfo *currSubtree = NZ( subtrees.getCurrent() );
1538 // there is always a structure for an existing subtree
1539 StylesheetStructure *currStruct = NZ( currSubtree -> getStructure() );
1540 // create new structure with precedence one higher
1541 //StylesheetStructure *newStruct = new StylesheetStructure(
1542 //currStruct -> getImportPrecedence() + 1);
1543 StylesheetStructure *newStruct = new StylesheetStructure(0);
1544
1545 // file newStruct into existing tree if stylesheet structures
1546 currStruct -> addImportStructure(S, newStruct);
1547 return newStruct;
1548 }
1549
findBestRule(Sit S,XSLElement * & ret,Context * c,QName * currMode,Bool importsOnly,SubtreeInfo * subtree)1550 eFlag Tree::findBestRule(
1551 Sit S,
1552 XSLElement *&ret,
1553 Context *c,
1554 QName *currMode,
1555 Bool importsOnly,
1556 SubtreeInfo *subtree /* NULL */)
1557 {
1558 SubtreeInfo *start = (importsOnly && subtree) ? subtree : subtrees[0];
1559 return NZ(start) -> getStructure() -> findBestRule(
1560 S, ret, c, currMode, importsOnly);
1561 }
1562
hasAnyStrippedName()1563 Bool Tree::hasAnyStrippedName() {
1564 if (hasAnyStripped == -1)
1565 hasAnyStripped = subtrees[0] -> getStructure() -> hasAnyStripped();
1566 return hasAnyStripped;
1567 }
1568
hasAnyPreservedName()1569 Bool Tree::hasAnyPreservedName() {
1570 if (hasAnyPreserved == -1)
1571 hasAnyPreserved = subtrees[0] -> getStructure() -> hasAnyPreserved();
1572 return hasAnyPreserved;
1573 }
1574
findStrippedName(EQName & name,int & prec,double & prio)1575 Bool Tree::findStrippedName(EQName &name, int &prec, double &prio)
1576 {
1577 return
1578 NZ(subtrees[0]) -> getStructure() ->
1579 findStrippedName(name, prec, prio);
1580 }
1581
findPreservedName(EQName & name,int & prec,double & prio)1582 Bool Tree::findPreservedName(EQName &name, int &prec, double &prio)
1583 {
1584 return
1585 NZ(subtrees[0]) -> getStructure() ->
1586 findPreservedName(name, prec, prio);
1587 }
1588
findRuleByName(QName & q)1589 XSLElement* Tree::findRuleByName(QName &q)
1590 {
1591 return NZ( subtrees[0] ) -> getStructure() -> findRuleByName(*this, q);
1592 }
1593
1594 /*
1595 eFlag Tree::resolveGlobals(Sit S, Context *c, Processor *proc)
1596 {
1597 sabassert(proc);
1598 QName temp;
1599 for (int i = 0; i < toplevelVars.number(); i++)
1600 {
1601 // resolve the global identified by pointer
1602 // the name does not matter
1603 temp.empty();
1604 E( proc -> resolveGlobal(S, c, temp, toplevelVars[i] -> getElement()) );
1605 }
1606 return OK;
1607 }
1608 */
1609
setUnparsedEntityUri(Str & name,Str & uri)1610 void Tree::setUnparsedEntityUri(Str &name, Str &uri)
1611 {
1612 unparsedEntities.appendConstruct(name, uri);
1613 }
1614
getUnparsedEntityUri(Str & name)1615 Str* Tree::getUnparsedEntityUri(Str &name)
1616 {
1617 return unparsedEntities.find(name);
1618 }
1619
pushPendingNS(Sit S,Tree * srcTree,NSList & other)1620 eFlag Tree::pushPendingNS(Sit S, Tree* srcTree, NSList &other)
1621 {
1622 NSList *lst = new(&theArena) NSList();
1623 lst -> swallow(S, other, srcTree, this);
1624 pendingNSList.append(lst);
1625 return OK;
1626 }
1627
popPendingNS(Sit S)1628 eFlag Tree::popPendingNS(Sit S)
1629 {
1630 pendingNSList.freelast(FALSE);
1631 return OK;
1632 }
1633
speakDebug()1634 void Tree::speakDebug()
1635 {
1636 DStr foo;
1637 getRoot().speak(foo, (SpeakMode)(SM_OFFICIAL | SM_INS_SPACES));
1638 printf("--------------------\n%s\n--------------------\n", (char*)foo);
1639 }
1640
dumpStructure(Sit S)1641 void Tree::dumpStructure(Sit S)
1642 {
1643 S.message(MT_LOG, L_SHEET_STRUCTURE, "", "");
1644 for (int i = 0; i < subtrees.number(); i++)
1645 {
1646 //count level
1647 DStr out = "";
1648 int level = 0;
1649 SubtreeInfo * si = subtrees[i];
1650 while (si)
1651 {
1652 if (level > 0) out += " ";
1653 level++;
1654 si = si -> getParentSubtree();
1655 }
1656
1657 out += subtrees[i] -> getBaseURI();
1658 S.message(MT_LOG, L_SHEET_ITEM, out, "");
1659 }
1660 }
1661
1662 //_TH_ v
1663 /****************************************
1664 T m p L i s t methods
1665 ****************************************/
1666
TmpList()1667 TmpList::TmpList():PList<Vertex *>()
1668 {
1669 #ifdef _TH_DEBUG
1670 puts("TmpList constructor");
1671 #endif
1672 //printf("TmpList constructor >%x<\n",this);
1673 }
1674
~TmpList()1675 TmpList::~TmpList()
1676 {
1677 #ifdef _TH_DEBUG
1678 puts("TmpList destructor");
1679 #endif
1680 // dump();
1681 freeall(FALSE);
1682 }
append(void * what)1683 void TmpList::append(void *what)
1684 {
1685 // printf("TmpList append\n");
1686 ((Vertex *)what)->ordinal=number();
1687 PList<Vertex *>::append((Vertex *)what);
1688 }
1689
rm(int n)1690 void TmpList::rm(int n)
1691 {
1692 // printf("TmpList rm >%d<\n",n);
1693 PList<Vertex *>::rm(n);
1694 for(int i=n;i<number();i++)
1695 (*this)[i]->ordinal=i;
1696 }
1697
freeall(Bool a)1698 void TmpList::freeall(Bool a)
1699 {
1700 #ifdef _TH_DEBUG
1701 printf("TmpList freeall(Bool)\n");
1702 #endif
1703 PList<Vertex *>::freeall(a);
1704 }
1705
dump(int p)1706 void TmpList::dump(int p)
1707 {
1708 /*
1709 Str vname;
1710 if(p==0) printf("TmpList.dump (%d item(s))\n", nItems);
1711 else printf("TmpList.dump %d (%d item(s))\n", p, nItems);
1712 for(int i=0; i<nItems; i++){
1713 ((*this)[i])->getOwner().expandQStr(toE((*this)[i]) -> getName(),vname);
1714 printf("%d:>%d< >%x< (%s)\n",i,((*this)[i])->ordinal,((*this)[i]),(char*)vname);
1715 }
1716 */
1717 };
1718
findNum(void * p) const1719 int TmpList::findNum(void *p) const
1720 {
1721 int i;
1722 for (i = number()-1; (i >= 0) && !((Vertex *)p == (*this)[i]); i--) {};
1723 return i;
1724 }
1725
rmP(void * p)1726 void TmpList::rmP(void *p)
1727 {
1728 rm(((Vertex *)p)->ordinal);
1729 }
1730 //_TH_ ^
1731
find(XSL_ATT what)1732 Attribute* AttsCache::find(XSL_ATT what)
1733 {
1734 int i;
1735 Attribute *a;
1736 int num = number();
1737 for (i = 0; i < num; i++)
1738 {
1739 // need to use a temporary variable
1740 // to get around Solaris template problem
1741 Vertex * pTemp = (*this)[i];
1742 a = cast(Attribute *, pTemp);
1743 if (a -> op == what)
1744 return a;
1745 };
1746 return NULL;
1747 }
1748
findNdx(const QName & attName)1749 int AttsCache::findNdx(const QName& attName)
1750 {
1751 int i;
1752 Attribute *a;
1753 int num = number();
1754 for (i = 0; i < num; i++)
1755 {
1756 // need to use a temporary variable
1757 // to get around Solaris template problem
1758 Vertex * pTemp = (*this)[i];
1759 a = toA(pTemp);
1760 if (attName == a -> getName())
1761 return i;
1762 };
1763 return -1;
1764 }
1765
find(const QName & attName)1766 Attribute* AttsCache::find(const QName& attName)
1767 {
1768 int ndx = findNdx(attName);
1769 // need to use a temporary variable
1770 // to get around Solaris template problem
1771 if (ndx != -1)
1772 {
1773 Vertex * pTemp = (*this)[ndx];
1774 return toA(pTemp);
1775 }
1776 else
1777 {
1778 return NULL;
1779 }
1780 }
1781