1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the  "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #include "Stylesheet.hpp"
20 
21 
22 
23 #include <algorithm>
24 
25 
26 
27 #include <xercesc/sax/AttributeList.hpp>
28 #include <xercesc/util/PlatformUtils.hpp>
29 
30 
31 
32 #include <xalanc/Include/STLHelper.hpp>
33 
34 
35 
36 #include <xalanc/XalanDOM/XalanDOMException.hpp>
37 
38 
39 
40 #include <xalanc/PlatformSupport/XalanMessageLoader.hpp>
41 
42 
43 
44 #include <xalanc/DOMSupport/DOMServices.hpp>
45 
46 
47 
48 #include <xalanc/XMLSupport/XMLParserLiaison.hpp>
49 
50 
51 
52 #include <xalanc/XPath/XObject.hpp>
53 #include <xalanc/XPath/XPath.hpp>
54 #include <xalanc/XPath/XalanQNameByReference.hpp>
55 
56 
57 
58 #include "Constants.hpp"
59 #include "ElemAttributeSet.hpp"
60 #include "ElemDecimalFormat.hpp"
61 #include "ElemTemplate.hpp"
62 #include "ElemTemplateElement.hpp"
63 #include "ElemVariable.hpp"
64 #include "ExtensionNSHandler.hpp"
65 #include "KeyTable.hpp"
66 #include "StylesheetConstructionContext.hpp"
67 #include "StylesheetExecutionContext.hpp"
68 #include "XalanMatchPatternData.hpp"
69 
70 
71 
72 namespace XALAN_CPP_NAMESPACE {
73 
74 
75 
76 const XalanDOMString            Stylesheet::s_emptyString(XalanMemMgrs::getDummyMemMgr());
77 
78 const Stylesheet::PatternTableVectorType    Stylesheet::s_emptyTemplateList(XalanMemMgrs::getDummyMemMgr());
79 
80 const XalanQNameByReference     Stylesheet::s_emptyQName;
81 
82 
83 
Stylesheet(StylesheetRoot & root,const XalanDOMString & baseIdentifier,StylesheetConstructionContext & constructionContext)84 Stylesheet::Stylesheet(
85         StylesheetRoot&                 root,
86         const XalanDOMString&           baseIdentifier,
87         StylesheetConstructionContext&  constructionContext) :
88     PrefixResolver(),
89     m_stylesheetRoot(root),
90     m_baseIdent(baseIdentifier,constructionContext.getMemoryManager()),
91     m_keyDeclarations(constructionContext.getMemoryManager()),
92     m_whitespaceElements(constructionContext.getMemoryManager()),
93     m_XSLTNamespaceURI(constructionContext.getXSLTNamespaceURI(),constructionContext.getMemoryManager()),
94     m_imports(constructionContext.getMemoryManager()),
95     m_importsSize(0),
96     m_namespaces(constructionContext.getMemoryManager()),
97     m_namespaceDecls(constructionContext.getMemoryManager()),
98     m_isWrapperless(false),
99     m_extensionNamespaces(constructionContext.getMemoryManager()),
100     m_firstTemplate(0),
101     m_includeStack(constructionContext.getMemoryManager()),
102     m_namedTemplates(constructionContext.getMemoryManager()),
103     m_topLevelVariables(constructionContext.getMemoryManager()),
104     m_XSLTVerDeclared(1.0L),
105     m_elementPatternTable(constructionContext.getMemoryManager()),
106     m_elementPatternTableEnd(m_elementPatternTable.end()),
107     m_elementAnyPatternList(constructionContext.getMemoryManager()),
108     m_attributePatternTable(constructionContext.getMemoryManager()),
109     m_attributePatternTableEnd(m_attributePatternTable.end()),
110     m_attributeAnyPatternList(constructionContext.getMemoryManager()),
111     m_textPatternList(constructionContext.getMemoryManager()),
112     m_commentPatternList(constructionContext.getMemoryManager()),
113     m_rootPatternList(constructionContext.getMemoryManager()),
114     m_piPatternList(constructionContext.getMemoryManager()),
115     m_nodePatternList(constructionContext.getMemoryManager()),
116     m_patternCount(0),
117     m_elemDecimalFormats(constructionContext.getMemoryManager()),
118     m_namespacesHandler(constructionContext.getMemoryManager())
119 {
120     if (m_baseIdent.empty() == true)
121     {
122         m_includeStack.push_back(m_baseIdent);
123     }
124     else
125     {
126         try
127         {
128             const GetCachedString   theGuard(constructionContext);
129 
130             XalanDOMString&     urlString = theGuard.get();
131 
132             constructionContext.getURLStringFromString(m_baseIdent, urlString);
133 
134             if (urlString.empty() == false)
135             {
136                 m_includeStack.push_back(urlString);
137 
138                 m_baseIdent = urlString;
139             }
140         }
141         catch(const xercesc::XMLPlatformUtilsException&)
142         {
143             // Assume that any exception here relates to get the urlString from
144             // m_baseIdent.  We'll assume that it's just a fake base identifier
145             // since the parser will throw the real error if the base identifier
146             // can't be resolved.
147             m_includeStack.push_back(baseIdentifier);
148         }
149     }
150 }
151 
152 
153 
154 Stylesheet*
create(MemoryManager & theManager,StylesheetRoot & root,const XalanDOMString & baseIdentifier,StylesheetConstructionContext & constructionContext)155 Stylesheet::create(
156             MemoryManager&                  theManager,
157             StylesheetRoot&                 root,
158             const XalanDOMString&           baseIdentifier,
159             StylesheetConstructionContext&  constructionContext)
160 {
161     Stylesheet* theInstance;
162 
163     return XalanConstruct(
164             theManager,
165             theInstance,
166             root,
167             baseIdentifier,
168             constructionContext);
169 }
170 
171 
172 
~Stylesheet()173 Stylesheet::~Stylesheet()
174 {
175     using std::for_each;
176 
177     // Clean up all entries in the imports vector.
178     for_each(
179         m_imports.begin(),
180         m_imports.end(),
181         DeleteFunctor<Stylesheet>(m_imports.getMemoryManager()));
182 
183     // Clean up the decimal formats vector
184     for_each(
185         m_elemDecimalFormats.begin(),
186         m_elemDecimalFormats.end(),
187         DeleteFunctor<ElemDecimalFormat>(m_elemDecimalFormats.getMemoryManager()));
188 
189 
190     for_each(
191         m_extensionNamespaces.begin(),
192         m_extensionNamespaces.end(),
193         makeMapValueDeleteFunctor(m_extensionNamespaces));
194 
195 }
196 
197 
198 
199 void
error(StylesheetConstructionContext & theContext,XalanMessages::Codes theErrorCode,const Locator * theLocator,const XalanDOMChar * theParam1,const XalanDOMChar * theParam2,const XalanDOMChar * theParam3) const200 Stylesheet::error(
201             StylesheetConstructionContext&  theContext,
202             XalanMessages::Codes            theErrorCode,
203             const Locator*                  theLocator,
204             const XalanDOMChar*             theParam1,
205             const XalanDOMChar*             theParam2,
206             const XalanDOMChar*             theParam3) const
207 {
208     const GetCachedString   theGuard(theContext);
209 
210     theContext.problem(
211         StylesheetConstructionContext::eXSLTProcessor,
212         StylesheetConstructionContext::eError,
213         XalanMessageLoader::getMessage(
214             theGuard.get(),
215             theErrorCode,
216             theParam1,
217             theParam2,
218             theParam3),
219         theLocator,
220         0);
221 }
222 
223 
224 
225 ElemTemplateElement*
initWrapperless(StylesheetConstructionContext & constructionContext,const Locator * locator)226 Stylesheet::initWrapperless(
227             StylesheetConstructionContext&  constructionContext,
228             const Locator*                  locator)
229 {
230     if (m_isWrapperless == true)
231     {
232         error(
233             constructionContext,
234             XalanMessages::StylesheetHasWrapperlessTemplate,
235             locator);
236     }
237 
238     assert(m_firstTemplate == 0);
239 
240     m_isWrapperless = true;
241 
242 
243     AttributeListImpl   templateAttrs(constructionContext.getMemoryManager());
244 
245     templateAttrs.addAttribute(Constants::ATTRNAME_NAME.c_str(),
246                                Constants::ATTRTYPE_CDATA.c_str(),
247                                Constants::ATTRVAL_SIMPLE.c_str());
248 
249     ElemTemplateElement* const  theNewTemplate =
250         constructionContext.createElement(
251             StylesheetConstructionContext::ELEMNAME_TEMPLATE,
252             *this,
253             templateAttrs,
254             locator);
255 
256     theNewTemplate->addToStylesheet(constructionContext, *this);
257 
258     assert(m_firstTemplate == theNewTemplate);
259 
260     return theNewTemplate;
261 }
262 
263 
264 
265 void
processKeyElement(const PrefixResolver & nsContext,const AttributeListType & atts,const Locator * locator,StylesheetConstructionContext & constructionContext)266 Stylesheet::processKeyElement(
267             const PrefixResolver&           nsContext,
268             const AttributeListType&        atts,
269             const Locator*                  locator,
270             StylesheetConstructionContext&  constructionContext)
271 {
272     const XalanQName*       theQName = 0;
273     XPath*                  matchAttr = 0;
274     XPath*                  useAttr = 0;
275 
276     const XalanSize_t   nAttrs = atts.getLength();
277 
278     for(XalanSize_t i = 0; i < nAttrs; i++)
279     {
280         const XalanDOMChar* const   aname = atts.getName(i);
281 
282         if (equals(aname, Constants::ATTRNAME_NAME))
283         {
284             theQName = constructionContext.createXalanQName(atts.getValue(i), m_namespaces, locator);
285 
286             // $$$TODO: It's not clear of this code will ever be executed, since
287             // constructing an invalid QName is not possibly right now.
288             assert(theQName->isValid() == true);
289             if (theQName->isValid() == false)
290             {
291                 error(
292                     constructionContext,
293                     XalanMessages::AttributeValueNotValidQName_2Param,
294                     locator,
295                     Constants::ATTRNAME_NAME.c_str(),
296                     atts.getValue(i));
297             }
298         }
299         else if(equals(aname, Constants::ATTRNAME_MATCH))
300         {
301             const GetCachedString   theGuard(constructionContext);
302 
303             XalanDOMString&     theBuffer = theGuard.get();
304 
305             theBuffer.assign(atts.getValue(i));
306 
307             matchAttr =
308                     constructionContext.createMatchPattern(
309                         0,
310                         theBuffer,
311                         nsContext,
312                         false,
313                         false);
314         }
315         else if(equals(aname, Constants::ATTRNAME_USE))
316         {
317             useAttr =
318                     constructionContext.createXPath(
319                         0,
320                         atts.getValue(i),
321                         nsContext,
322                         false,
323                         false);
324         }
325         else if (isAttrOK(aname, atts, i, constructionContext) == false)
326         {
327             error(
328                 constructionContext,
329                 XalanMessages::ElementHasIllegalAttribute_2Param,
330                 locator,
331                 Constants::ELEMNAME_KEY_WITH_PREFIX_STRING.c_str(),
332                 aname);
333         }
334     }
335 
336     if (0 == theQName)
337     {
338         error(
339             constructionContext,
340             XalanMessages::ElementRequiresAttribute_2Param,
341             locator,
342             Constants::ELEMNAME_KEY_WITH_PREFIX_STRING.c_str(),
343             Constants::ATTRNAME_NAME.c_str());
344     }
345 
346     if (0 == matchAttr)
347     {
348         error(
349             constructionContext,
350             XalanMessages::ElementRequiresAttribute_2Param,
351             locator,
352             Constants::ELEMNAME_KEY_WITH_PREFIX_STRING.c_str(),
353             Constants::ATTRNAME_MATCH.c_str());
354     }
355 
356     if (0 == useAttr)
357     {
358         error(
359             constructionContext,
360             XalanMessages::ElementRequiresAttribute_2Param,
361             locator,
362             Constants::ELEMNAME_KEY_WITH_PREFIX_STRING.c_str(),
363             Constants::ATTRNAME_USE.c_str());
364     }
365 
366     m_keyDeclarations.push_back(
367         KeyDeclaration(
368             *theQName,
369             *matchAttr,
370             *useAttr,
371             m_baseIdent,
372             XalanLocator::getLineNumber(locator),
373             XalanLocator::getColumnNumber(locator)));
374 }
375 
376 
377 
378 void
pushNamespaces(const AttributeListType & atts)379 Stylesheet::pushNamespaces(const AttributeListType&     atts)
380 {
381     const XalanSize_t       nAttrs = atts.getLength();
382 
383     NamespaceVectorType     namespaces(getMemoryManager());
384 
385     XalanDOMString          prefix(getMemoryManager());
386 
387     for(XalanSize_t i = 0; i < nAttrs; i++)
388     {
389         const XalanDOMChar* const   aname = atts.getName(i);
390         const XalanDOMChar* const   value = atts.getValue(i);
391 
392         const bool  isPrefix = startsWith(aname, DOMServices::s_XMLNamespaceWithSeparator);
393 
394         if (equals(aname, DOMServices::s_XMLNamespace) || isPrefix)
395         {
396             if (isPrefix == false)
397             {
398                 prefix.clear();
399             }
400             else
401             {
402                 substring(aname, prefix, DOMServices::s_XMLNamespaceWithSeparatorLength);
403             }
404 
405             const NameSpace     newNS(prefix, XalanDOMString(value, getMemoryManager()), getMemoryManager());
406 
407             namespaces.push_back(newNS);
408         }
409     }
410 
411     m_namespaces.push_back(namespaces);
412 }
413 
414 
415 
416 class attrSetCompare
417 {
418 public:
419 
attrSetCompare(const ElemAttributeSet & theAttrSet)420     attrSetCompare(const ElemAttributeSet&  theAttrSet) :
421         m_attrSet(theAttrSet)
422     {
423     }
424 
425     bool
operator ()(const ElemAttributeSet * theRHS) const426     operator()(const ElemAttributeSet*  theRHS) const
427     {
428         assert(theRHS != 0);
429 
430         return m_attrSet == *theRHS;
431     }
432 
433 private:
434 
435     const ElemAttributeSet&     m_attrSet;
436 };
437 
438 
439 
440 static void
addToList(Stylesheet::PatternTableVectorType & theList,const XalanMatchPatternData * thePattern)441 addToList(
442             Stylesheet::PatternTableVectorType&     theList,
443             const XalanMatchPatternData*            thePattern)
444 {
445     assert(thePattern != 0);
446 
447     const double        thePatternPriority = thePattern->getPriorityOrDefault();
448     const XalanSize_t   thePatternPosition = thePattern->getPosition();
449 
450     typedef Stylesheet::PatternTableVectorType  PatternTableListType;
451     typedef PatternTableListType::iterator      iterator;
452 
453     iterator        theCurrent = theList.begin();
454 
455     const iterator  theEnd = theList.end();
456 
457     while (theCurrent != theEnd)
458     {
459         const double    theCurrentPriority = (*theCurrent)->getPriorityOrDefault();
460 
461         if (thePatternPriority > theCurrentPriority)
462         {
463             break;
464         }
465         else if (thePatternPriority == theCurrentPriority &&
466                  thePatternPosition > (*theCurrent)->getPosition())
467         {
468             break;
469         }
470 
471         ++theCurrent;
472     }
473 
474     theList.insert(theCurrent, thePattern);
475 }
476 
477 
478 
479 static void
addToTable(Stylesheet::PatternTableMapType & theTable,const Stylesheet::PatternTableVectorType & theList)480 addToTable(
481            Stylesheet::PatternTableMapType&             theTable,
482            const Stylesheet::PatternTableVectorType&    theList)
483 {
484     typedef Stylesheet::PatternTableMapType     PatternTableMapType;
485     typedef Stylesheet::PatternTableVectorType  PatternTableListType;
486 
487     PatternTableMapType::iterator               theCurrentTable = theTable.begin();
488     const PatternTableMapType::iterator         theTableEnd = theTable.end();
489     const PatternTableListType::const_iterator  theListEnd = theList.end();
490 
491     while(theCurrentTable != theTableEnd)
492     {
493         PatternTableListType::const_iterator    theCurrent = theList.begin();
494 
495         while(theCurrent != theListEnd)
496         {
497             addToList((*theCurrentTable).second, *theCurrent);
498 
499             ++theCurrent;
500         }
501 
502         ++theCurrentTable;
503     }
504 }
505 
506 
507 
508 void
addWhitespaceElement(const XalanSpaceNodeTester & theTester)509 Stylesheet::addWhitespaceElement(const XalanSpaceNodeTester&    theTester)
510 {
511     typedef WhitespaceElementsVectorType::iterator  iterator;
512 
513     const XPath::eMatchScore    theMatchScore = theTester.getMatchScore();
514 
515     iterator    i = m_whitespaceElements.begin();
516 
517     while(i != m_whitespaceElements.end())
518     {
519         if (theMatchScore >= (*i).getMatchScore())
520         {
521             break;
522         }
523         else
524         {
525             ++i;
526         }
527     }
528 
529     m_whitespaceElements.insert(i, theTester);
530 }
531 
532 
533 
534 void
postConstruction(StylesheetConstructionContext & constructionContext)535 Stylesheet::postConstruction(StylesheetConstructionContext&     constructionContext)
536 {
537     KeyDeclarationVectorType::size_type         theKeyDeclarationsCount = 0;
538     WhitespaceElementsVectorType::size_type     theWhitespaceElementsCount = 0;
539 
540     {
541         m_importsSize = m_imports.size();
542 
543         // Call postConstruction() on any imported stylesheets, in reverse order,
544         // so namespace aliases are processed properly. Also, get any key
545         // declarations and preserve/strip space information.
546         const StylesheetVectorType::reverse_iterator    theEnd = m_imports.rend();
547         StylesheetVectorType::reverse_iterator          i = m_imports.rbegin();
548 
549         while(i != theEnd)
550         {
551             (*i)->postConstruction(constructionContext);
552 
553             m_namespacesHandler.copyNamespaceAliases((*i)->getNamespacesHandler());
554 
555             theKeyDeclarationsCount += (*i)->m_keyDeclarations.size();
556             theWhitespaceElementsCount += (*i)->m_whitespaceElements.size();
557 
558             ++i;
559         }
560     }
561 
562     {
563         // Call postConstruction() on any imported stylesheets, in import order,
564         // and process preserve/strip space information.
565         const StylesheetVectorType::iterator    theEnd = m_imports.end();
566         StylesheetVectorType::iterator          i = m_imports.begin();
567 
568         m_keyDeclarations.reserve(
569             m_keyDeclarations.size() + theKeyDeclarationsCount);
570 
571         m_whitespaceElements.reserve(
572             m_whitespaceElements.size() + theWhitespaceElementsCount);
573 
574         while(i != theEnd)
575         {
576             m_keyDeclarations.insert(
577                 m_keyDeclarations.end(),
578                 (*i)->m_keyDeclarations.begin(),
579                 (*i)->m_keyDeclarations.end());
580 
581             {
582                 KeyDeclarationVectorType temp(getMemoryManager());
583                 temp.swap((*i)->m_keyDeclarations);
584             }
585 
586             m_whitespaceElements.insert(
587                 m_whitespaceElements.end(),
588                 (*i)->m_whitespaceElements.begin(),
589                 (*i)->m_whitespaceElements.end());
590 
591             {
592                 WhitespaceElementsVectorType temp(getMemoryManager());
593                 temp.swap((*i)->m_whitespaceElements);
594             }
595 
596             ++i;
597         }
598     }
599 
600     // Call postConstruction() on our own namespaces handler...
601     m_namespacesHandler.postConstruction(constructionContext);
602 
603     {
604         for (ElemTemplateElement* node = m_firstTemplate;
605              node != 0;
606              node = node->getNextSiblingElem())
607         {
608             node->postConstruction(constructionContext, m_namespacesHandler);
609         }
610     }
611 
612     {
613         for (ElemVariableVectorType::iterator it = m_topLevelVariables.begin();
614              it != m_topLevelVariables.end();
615              ++it)
616         {
617             (*it)->postConstruction(constructionContext, m_namespacesHandler);
618         }
619     }
620 
621     addToTable(m_elementPatternTable, m_elementAnyPatternList);
622     addToTable(m_attributePatternTable, m_attributeAnyPatternList);
623 }
624 
625 
626 
627 bool
isAttrOK(const XalanDOMChar * attrName,const AttributeListType &,XalanSize_t,StylesheetConstructionContext & constructionContext) const628 Stylesheet::isAttrOK(
629             const XalanDOMChar*             attrName,
630             const AttributeListType&        /* atts */,
631             XalanSize_t                     /* which */,
632             StylesheetConstructionContext&  constructionContext) const
633 {
634     // Namespace declarations are OK by definition
635     bool attrOK =
636         equals(
637             attrName,
638             DOMServices::s_XMLNamespace) ||
639         startsWith(attrName, DOMServices::s_XMLNamespaceWithSeparator);
640 
641     if(!attrOK)
642     {
643         // Others are OK if their prefix has been
644         // bound to a non-null Namespace URI other than XSLT's
645         const XalanDOMString::size_type     indexOfNSSep = indexOf(attrName, XalanUnicode::charColon);
646 
647         if(indexOfNSSep < length(attrName))
648         {
649             const GetCachedString   theGuard(constructionContext);
650 
651             XalanDOMString&     prefix = theGuard.get();
652 
653             prefix.assign(attrName, indexOfNSSep);
654 
655             const XalanDOMString*   ns = getNamespaceForPrefixFromStack(prefix);
656 
657             attrOK = ns != 0 && !ns->empty() && *ns != constructionContext.getXSLTNamespaceURI();
658         }
659         else if (m_XSLTVerDeclared > constructionContext.getXSLTVersionSupported())
660         {
661             attrOK = true;
662         }
663     }
664 
665     return attrOK;
666 }
667 
668 
669 
670 const XalanDOMString*
getNamespaceFromStack(const XalanDOMChar * nodeName,XalanDOMString & theBuffer) const671 Stylesheet::getNamespaceFromStack(const XalanDOMChar*   nodeName,
672                                   XalanDOMString&       theBuffer) const
673 {
674     assert(nodeName != 0);
675 
676     const XalanDOMString::size_type     indexOfNSSep = indexOf(nodeName, XalanUnicode::charColon);
677 
678     if (indexOfNSSep == length(nodeName))
679     {
680         return getNamespaceForPrefixFromStack(s_emptyString);
681     }
682     else
683     {
684         theBuffer.assign(nodeName, indexOfNSSep);
685 
686         return getNamespaceForPrefixFromStack(theBuffer);
687     }
688 }
689 
690 
691 
692 const XalanDOMString*
getNamespaceForPrefix(const XalanDOMString & prefix,StylesheetConstructionContext & constructionContext) const693 Stylesheet::getNamespaceForPrefix(
694             const XalanDOMString&           prefix,
695             StylesheetConstructionContext&  constructionContext) const
696 {
697     const XalanDOMString* const     theURI = getNamespaceForPrefix(prefix);
698 
699     if (theURI == 0)
700     {
701         error(
702             constructionContext,
703             XalanMessages::PrefixIsNotDeclared_1Param,
704             constructionContext.getLocatorFromStack(),
705             prefix.c_str());
706     }
707 
708     return theURI;
709 }
710 
711 
712 
713 const XalanDOMString*
getNamespaceForPrefix(const XalanDOMChar * prefix,StylesheetConstructionContext & constructionContext) const714 Stylesheet::getNamespaceForPrefix(
715             const XalanDOMChar*             prefix,
716             StylesheetConstructionContext&  constructionContext) const
717 {
718     const GetCachedString   theGuard(constructionContext);
719 
720     XalanDOMString&     theTemp = theGuard.get();
721 
722     theTemp.assign(prefix);
723 
724     return getNamespaceForPrefix(theTemp, constructionContext);
725 }
726 
727 
728 
729 bool
getYesOrNo(const XalanDOMChar * aname,const XalanDOMChar * val,StylesheetConstructionContext & constructionContext) const730 Stylesheet::getYesOrNo(
731             const XalanDOMChar*             aname,
732             const XalanDOMChar*             val,
733             StylesheetConstructionContext&  constructionContext) const
734 {
735     if(equals(val, Constants::ATTRVAL_YES))
736     {
737         return true;
738     }
739     else if(equals(val, Constants::ATTRVAL_NO))
740     {
741         return false;
742     }
743     else
744     {
745         error(
746             constructionContext,
747             XalanMessages::AttributeMustBe_3Params,
748             constructionContext.getLocatorFromStack(),
749             aname,
750             Constants::ATTRVAL_YES.c_str(),
751             Constants::ATTRVAL_NO.c_str());
752 
753         return false;
754     }
755 }
756 
757 
758 
759 void
addTemplate(ElemTemplate * theTemplate,StylesheetConstructionContext & constructionContext)760 Stylesheet::addTemplate(
761             ElemTemplate*                   theTemplate,
762             StylesheetConstructionContext&  constructionContext)
763 {
764     assert(theTemplate != 0);
765 
766     if (m_isWrapperless == true)
767     {
768         if (m_firstTemplate != 0)
769         {
770             error(
771                 constructionContext,
772                 XalanMessages::StylesheetHasWrapperlessTemplate,
773                 theTemplate->getLocator());
774         }
775         else
776         {
777             m_firstTemplate = theTemplate;
778         }
779     }
780     else if (0 == m_firstTemplate)
781     {
782         m_firstTemplate = theTemplate;
783     }
784     else
785     {
786         ElemTemplateElement*    next = m_firstTemplate;
787 
788         // Find the last one, then append the new one.
789         while (0 != next)
790         {
791             if (0 == next->getNextSiblingElem())
792             {
793                 next->setNextSiblingElem(theTemplate);
794                 theTemplate->setNextSiblingElem(0); // just to play it safe.
795                 theTemplate->setPreviousSiblingElem(next);
796                 break;
797             }
798 
799             next = next->getNextSiblingElem();
800         }
801     }
802 
803     // If it's a named template, then we need to
804     // and it to the map of named templates.
805     const XalanQName&   theName = theTemplate->getNameAttribute();
806 
807     if (theName.isEmpty() == false)
808     {
809         if (m_namedTemplates.find(theName) == m_namedTemplates.end())
810         {
811             m_namedTemplates[theName] = theTemplate;
812         }
813         else
814         {
815             const GetCachedString   theGuard(constructionContext);
816 
817             error(
818                 constructionContext,
819                 XalanMessages::StylesheetHasDuplicateNamedTemplate_1Param,
820                 theTemplate->getLocator(),
821                 theName.format(theGuard.get()).c_str());
822         }
823     }
824 
825     // Now, process the match pattern associated with the
826     // template.
827     const XPath* const  xp = theTemplate->getMatchPattern();
828 
829     if (0 != xp)
830     {
831         /* Each string has a list of pattern tables associated with it; if the
832          * string is not in the map, then create a list of pattern tables with one
833          * entry for the string, otherwise add to the existing pattern table list
834          * for that string
835          */
836         typedef XPath::TargetDataVectorType     TargetDataVectorType;
837 
838         TargetDataVectorType    data(constructionContext.getMemoryManager());
839 
840         xp->getTargetData(data);
841 
842         TargetDataVectorType::size_type nTargets =
843                 data.size();
844 
845         if (nTargets != 0)
846         {
847             const GetCachedString   theGuard(constructionContext);
848 
849             XalanDOMString& tempString = theGuard.get();
850 
851             for (TargetDataVectorType::size_type i = 0; i < nTargets; ++i)
852             {
853                 assert(data[i].getString() != 0);
854 
855                 tempString = data[i].getString();
856 
857                 const XalanMatchPatternData* const  newMatchPat =
858                     constructionContext.createXalanMatchPatternData(
859                         *theTemplate,
860                         m_patternCount,
861                         tempString,
862                         *xp,
863                         xp->getExpression().getCurrentPattern(),
864                         data[i].getDefaultPriority());
865 
866                 ++m_patternCount;
867 
868                 // Always put things on the front of the list, so
869                 // templates later in the stylesheet are always
870                 // selected first.
871                 if (equals(tempString, XPath::PSEUDONAME_TEXT) == true)
872                 {
873                     addToList(m_textPatternList, newMatchPat);
874                 }
875                 else if (equals(tempString, XPath::PSEUDONAME_COMMENT) == true)
876                 {
877                     addToList(m_commentPatternList, newMatchPat);
878                 }
879                 else if (equals(tempString, XPath::PSEUDONAME_ROOT) == true)
880                 {
881                     addToList(m_rootPatternList, newMatchPat);
882                 }
883                 else if (equals(tempString, XPath::PSEUDONAME_PI) == true)
884                 {
885                     addToList(m_piPatternList, newMatchPat);
886                 }
887                 else if (equals(tempString, XPath::PSEUDONAME_NODE) == true)
888                 {
889                     addToList(m_nodePatternList, newMatchPat);
890 
891                     addToList(m_elementAnyPatternList, newMatchPat);
892                     addToList(m_attributeAnyPatternList, newMatchPat);
893                     addToList(m_commentPatternList, newMatchPat);
894                     addToList(m_textPatternList, newMatchPat);
895                     addToList(m_piPatternList, newMatchPat);
896                 }
897                 else if (equals(tempString, XPath::PSEUDONAME_ANY) == true)
898                 {
899                     if (data[i].getTargetType() == XPath::TargetData::eElement)
900                     {
901                         addToList(m_elementAnyPatternList, newMatchPat);
902                     }
903                     else if (data[i].getTargetType() == XPath::TargetData::eAttribute)
904                     {
905                         addToList(m_attributeAnyPatternList, newMatchPat);
906                     }
907                     else if (data[i].getTargetType() == XPath::TargetData::eAny)
908                     {
909                         addToList(m_elementAnyPatternList, newMatchPat);
910                         addToList(m_attributeAnyPatternList, newMatchPat);
911                     }
912                 }
913                 else
914                 {
915                     if (data[i].getTargetType() == XPath::TargetData::eElement)
916                     {
917                         addToList(m_elementPatternTable[tempString], newMatchPat);
918                     }
919                     else if (data[i].getTargetType() == XPath::TargetData::eAttribute)
920                     {
921                         addToList(m_attributePatternTable[tempString], newMatchPat);
922                     }
923                 }
924             }
925         }
926     }
927 }
928 
929 
930 
931 const ElemTemplate*
findNamedTemplate(const XalanQName & qname) const932 Stylesheet::findNamedTemplate(const XalanQName&     qname) const
933 {
934     const ElemTemplateMapType::const_iterator   it = m_namedTemplates.find(qname);
935 
936     if(it != m_namedTemplates.end())
937     {
938         return (*it).second;
939     }
940     else
941     {
942         const ElemTemplate*     namedTemplate = 0;
943 
944         // Look for the template in the imports
945         const StylesheetVectorType::size_type   importsCount = m_imports.size();
946 
947         for(StylesheetVectorType::size_type i = 0; i < importsCount; ++i)
948         {
949             const Stylesheet* const stylesheet = m_imports[i];
950 
951             namedTemplate = stylesheet->findNamedTemplate(qname);
952 
953             if(0 != namedTemplate)
954                 break;
955         }
956 
957         return namedTemplate;
958     }
959 }
960 
961 
962 
963 void
addObjectIfNotFound(const XalanMatchPatternData * thePattern,PatternTableVectorType & theVector)964 Stylesheet::addObjectIfNotFound(
965             const XalanMatchPatternData*    thePattern,
966             PatternTableVectorType&         theVector)
967 {
968     using std::find;
969 
970     const PatternTableVectorType::const_iterator    theResult =
971         find(
972                 theVector.begin(),
973                 theVector.end(),
974                 thePattern);
975 
976     // Did we find it?
977     if(theResult == theVector.end())
978     {
979         theVector.push_back(thePattern);
980     }
981 }
982 
983 
984 
985 inline void
addObjectIfNotFound(const XalanMatchPatternData * thePattern,const XalanMatchPatternData * thePatternArray[],XalanSize_t & thePatternArraySize)986 Stylesheet::addObjectIfNotFound(
987             const XalanMatchPatternData*    thePattern,
988             const XalanMatchPatternData*    thePatternArray[],
989             XalanSize_t&                    thePatternArraySize)
990 {
991     assert(thePattern != 0 && thePatternArray != 0);
992 
993     if (thePatternArraySize == 0)
994     {
995         thePatternArray[0] = thePattern;
996 
997         ++thePatternArraySize;
998     }
999     else
1000     {
1001         XalanSize_t     i = 0;
1002 
1003         while(i < thePatternArraySize)
1004         {
1005             if (thePatternArray[i] != thePattern)
1006             {
1007                 ++i;
1008             }
1009             else
1010             {
1011                 break;
1012             }
1013         }
1014 
1015         if (i == thePatternArraySize)
1016         {
1017             thePatternArray[thePatternArraySize++] = thePattern;
1018         }
1019     }
1020 }
1021 
1022 
1023 
1024 inline const Stylesheet::PatternTableVectorType*
locateElementMatchPatternDataList(const XalanDOMString & theName) const1025 Stylesheet::locateElementMatchPatternDataList(const XalanDOMString&     theName) const
1026 {
1027     assert(m_elementPatternTableEnd == m_elementPatternTable.end());
1028 
1029     const PatternTableMapType::const_iterator   i =
1030         m_elementPatternTable.find(theName);
1031 
1032     if (i != m_elementPatternTableEnd)
1033     {
1034         return &(*i).second;
1035     }
1036     else
1037     {
1038         return &m_elementAnyPatternList;
1039     }
1040 }
1041 
1042 
1043 
1044 inline const Stylesheet::PatternTableVectorType*
locateAttributeMatchPatternDataList(const XalanDOMString & theName) const1045 Stylesheet::locateAttributeMatchPatternDataList(const XalanDOMString&   theName) const
1046 {
1047     assert(m_attributePatternTableEnd == m_attributePatternTable.end());
1048 
1049     const PatternTableMapType::const_iterator   i =
1050         m_attributePatternTable.find(theName);
1051 
1052     if (i != m_attributePatternTableEnd)
1053     {
1054         return &(*i).second;
1055     }
1056     else
1057     {
1058         return &m_attributeAnyPatternList;
1059     }
1060 }
1061 
1062 
1063 
1064 inline const Stylesheet::PatternTableVectorType*
locateMatchPatternDataList(const XalanNode & theNode,XalanNode::NodeType targetNodeType) const1065 Stylesheet::locateMatchPatternDataList(
1066             const XalanNode&        theNode,
1067             XalanNode::NodeType     targetNodeType) const
1068 {
1069     assert(theNode.getNodeType() == targetNodeType);
1070 
1071     switch(targetNodeType)
1072     {
1073     case XalanNode::ELEMENT_NODE:
1074         return locateElementMatchPatternDataList(DOMServices::getLocalNameOfNode(theNode));
1075         break;
1076 
1077     case XalanNode::PROCESSING_INSTRUCTION_NODE:
1078         return &m_piPatternList;
1079         break;
1080 
1081     case XalanNode::ATTRIBUTE_NODE:
1082         if ((DOMServices::isNamespaceDeclaration(static_cast<const XalanAttr&>(theNode)) == true))
1083         {
1084             return &s_emptyTemplateList;
1085         }
1086         else
1087         {
1088             return locateAttributeMatchPatternDataList(DOMServices::getLocalNameOfNode(theNode));
1089         }
1090         break;
1091 
1092     case XalanNode::CDATA_SECTION_NODE:
1093     case XalanNode::TEXT_NODE:
1094         return &m_textPatternList;
1095         break;
1096 
1097     case XalanNode::COMMENT_NODE:
1098         return &m_commentPatternList;
1099         break;
1100 
1101     case XalanNode::DOCUMENT_NODE:
1102     case XalanNode::DOCUMENT_FRAGMENT_NODE:
1103         return &m_rootPatternList;
1104         break;
1105 
1106     default:
1107         break;
1108     }
1109 
1110     return &m_nodePatternList;
1111 }
1112 
1113 
1114 
1115 inline const ElemTemplate*
findTemplateInImports(StylesheetExecutionContext & executionContext,XalanNode * targetNode,XalanNode::NodeType targetNodeType,const XalanQName & mode) const1116 Stylesheet::findTemplateInImports(
1117             StylesheetExecutionContext&     executionContext,
1118             XalanNode*                      targetNode,
1119             XalanNode::NodeType             targetNodeType,
1120             const XalanQName&               mode) const
1121 {
1122     assert(targetNode->getNodeType() == targetNodeType);
1123     assert(m_importsSize == m_imports.size());
1124 
1125     for(StylesheetVectorType::size_type i = 0; i < m_importsSize; i++)
1126     {
1127         const Stylesheet* const     stylesheet =
1128             m_imports[i];
1129 
1130         const ElemTemplate* const   bestMatchedRule =
1131             stylesheet->findTemplate(
1132                 executionContext,
1133                 targetNode,
1134                 targetNodeType,
1135                 mode,
1136                 false);
1137 
1138         if(bestMatchedRule != 0)
1139         {
1140             return bestMatchedRule;
1141         }
1142     }
1143 
1144     return 0;
1145 }
1146 
1147 
1148 
1149 const ElemTemplate*
findTemplate(StylesheetExecutionContext & executionContext,XalanNode * targetNode,XalanNode::NodeType targetNodeType,const XalanQName & mode,bool onlyUseImports) const1150 Stylesheet::findTemplate(
1151             StylesheetExecutionContext&     executionContext,
1152             XalanNode*                      targetNode,
1153             XalanNode::NodeType             targetNodeType,
1154             const XalanQName&               mode,
1155             bool                            onlyUseImports) const
1156 {
1157     assert(targetNode != 0);
1158     assert(targetNode->getNodeType() == targetNodeType);
1159 
1160     if(m_isWrapperless == true)
1161     {
1162         return m_firstTemplate;
1163     }
1164     else if (onlyUseImports == true)
1165     {
1166         return findTemplateInImports(executionContext, targetNode, targetNodeType, mode);
1167     }
1168     else
1169     {
1170         const ElemTemplate*     bestMatchedRule = 0;
1171 
1172         if (executionContext.getQuietConflictWarnings() == true)
1173         {
1174             // Points to the current list of match patterns.  Note
1175             // that this may point to more than one table.
1176             const PatternTableVectorType*   matchPatternList =
1177                     locateMatchPatternDataList(*targetNode, targetNodeType);
1178             assert(matchPatternList != 0);
1179 
1180             PatternTableVectorType::const_iterator      theCurrentEntry =
1181                     matchPatternList->begin();
1182 
1183             const PatternTableVectorType::const_iterator    theTableEnd =
1184                     matchPatternList->end();
1185 
1186             while (theCurrentEntry != theTableEnd)
1187             {
1188                 const XalanMatchPatternData*    matchPat = *theCurrentEntry;
1189                 assert(matchPat != 0);
1190 
1191                 const ElemTemplate* const   rule = matchPat->getTemplate();
1192                 assert(rule != 0);
1193 
1194                 // We'll be needing to match rules according to what
1195                 // mode we're in.
1196                 const XalanQName&   ruleMode = rule->getMode();
1197 
1198                 // The logic here should be that if we are not in a mode AND
1199                 // the rule does not have a node, then go ahead.
1200                 // OR if we are in a mode, AND the rule has a node,
1201                 // AND the rules match, then go ahead.
1202                 const bool  haveMode = !mode.isEmpty();
1203                 const bool  haveRuleMode = !ruleMode.isEmpty();
1204 
1205                 if ((!haveMode && !haveRuleMode) ||
1206                     (haveMode && haveRuleMode && ruleMode.equals(mode)))
1207                 {
1208                     const XPath* const  xpath = matchPat->getExpression();
1209 
1210                     XPath::eMatchScore  score =
1211                                 xpath->getMatchScore(targetNode, *this, executionContext);
1212 
1213                     if(XPath::eMatchScoreNone != score)
1214                     {
1215                         bestMatchedRule = rule;
1216 
1217                         break;
1218                     }
1219                 }
1220 
1221                 ++theCurrentEntry;
1222             }
1223 
1224             if(0 == bestMatchedRule)
1225             {
1226                 bestMatchedRule = findTemplateInImports(executionContext, targetNode, targetNodeType, mode);
1227             }
1228         }
1229         else
1230         {
1231             const PatternTableVectorType*   matchPatternList =
1232                     locateMatchPatternDataList(*targetNode, targetNodeType);
1233             assert(matchPatternList != 0);
1234 
1235             PatternTableVectorType::const_iterator      theCurrentEntry =
1236                     matchPatternList->begin();
1237 
1238             const PatternTableVectorType::const_iterator    theTableEnd =
1239                     matchPatternList->end();
1240 
1241             if (theCurrentEntry != theTableEnd)
1242             {
1243                 const XalanMatchPatternData*    bestMatchedPattern = 0; // Syncs with bestMatchedRule
1244                 const double            matchScoreNoneValue =
1245                     XPath::getMatchScoreValue(XPath::eMatchScoreNone);
1246 
1247                 double                  bestMatchPatPriority = matchScoreNoneValue;
1248 
1249                 XalanSize_t             nConflicts = 0;
1250 
1251                 // Use a stack-based array when possible...
1252                 const XalanMatchPatternData*    conflictsArray[100];
1253 
1254                 XalanVector<const XalanMatchPatternData*>   conflictsVector(executionContext.getMemoryManager());
1255 
1256                 const XalanMatchPatternData**   conflicts = 0;
1257 
1258                 const XalanDOMString*           prevPat = 0;
1259                 const XalanMatchPatternData*    prevMatchPat = 0;
1260 
1261                 do
1262                 {
1263                     const XalanMatchPatternData*    matchPat = *theCurrentEntry;
1264                     double                  matchPatPriority = matchScoreNoneValue;
1265                     assert(matchPat != 0);
1266 
1267                     const ElemTemplate* const   rule = matchPat->getTemplate();
1268                     assert(rule != 0);
1269 
1270                     // We'll be needing to match rules according to what
1271                     // mode we're in.
1272                     const XalanQName&   ruleMode = rule->getMode();
1273 
1274                     // The logic here should be that if we are not in a mode AND
1275                     // the rule does not have a node, then go ahead.
1276                     // OR if we are in a mode, AND the rule has a node,
1277                     // AND the rules match, then go ahead.
1278                     const bool  haveMode = !mode.isEmpty();
1279                     const bool  haveRuleMode = !ruleMode.isEmpty();
1280 
1281                     if ((!haveMode && !haveRuleMode) ||
1282                         (haveMode && haveRuleMode && ruleMode.equals(mode)))
1283                     {
1284                         const XalanDOMString*   patterns = matchPat->getPattern();
1285                         assert(patterns != 0);
1286 
1287                         if(!patterns->empty() &&
1288                            !(prevMatchPat != 0 &&
1289                              (prevPat != 0 && equals(*prevPat, *patterns)) &&
1290                              prevMatchPat->getTemplate()->getPriority() == matchPat->getTemplate()->getPriority()))
1291                         {
1292                             prevPat = patterns;
1293                             prevMatchPat = matchPat;
1294                             matchPatPriority = matchScoreNoneValue;
1295 
1296                             const XPath* const  xpath = matchPat->getExpression();
1297 
1298                             XPath::eMatchScore  score =
1299                                         xpath->getMatchScore(targetNode, *this, executionContext);
1300 
1301                             if(XPath::eMatchScoreNone != score)
1302                             {
1303                                 const double priorityVal = rule->getPriority();
1304                                 const double priorityOfRule
1305                                               = (matchScoreNoneValue != priorityVal)
1306                                               ? priorityVal : XPath::getMatchScoreValue(score);
1307 
1308                                 matchPatPriority = priorityOfRule;
1309                                 const double priorityOfBestMatched =
1310                                                 (0 != bestMatchedPattern) ?
1311                                                         bestMatchPatPriority :
1312                                                         matchScoreNoneValue;
1313 
1314                                 if(priorityOfRule > priorityOfBestMatched)
1315                                 {
1316                                     nConflicts = 0;
1317 
1318                                     bestMatchedRule = rule;
1319                                     bestMatchedPattern = matchPat;
1320                                     bestMatchPatPriority = matchPatPriority;
1321                                 }
1322                                 else if(priorityOfRule == priorityOfBestMatched)
1323                                 {
1324                                     if (conflicts == 0)
1325                                     {
1326                                         if (m_patternCount > sizeof(conflictsArray) / sizeof(conflictsArray[0]))
1327                                         {
1328                                             conflictsVector.resize(m_patternCount);
1329 
1330                                             conflicts = conflictsVector.begin();
1331                                         }
1332                                         else
1333                                         {
1334                                             conflicts = conflictsArray;
1335                                         }
1336                                     }
1337 
1338                                     assert(conflicts != 0);
1339 
1340                                     // Add the best matched pattern so far.
1341                                     addObjectIfNotFound(bestMatchedPattern, conflicts, nConflicts);
1342 
1343                                     // Add the pattern that caused the conflict...
1344                                     conflicts[nConflicts++] = matchPat;
1345 
1346                                     bestMatchedRule = rule;
1347                                     bestMatchedPattern = matchPat;
1348                                     bestMatchPatPriority = matchPatPriority;
1349                                 }
1350                             }
1351                         }
1352                     }
1353 
1354                     ++theCurrentEntry;
1355 
1356                 } while(theCurrentEntry != theTableEnd);
1357 
1358                 if(nConflicts > 0)
1359                 {
1360                     assert(conflicts != 0 && nConflicts <= m_patternCount);
1361 
1362                     // Since the templates are arranged by their
1363                     // priority and reverse order in the stylesheet,
1364                     // the template with the highest priority that
1365                     // was last in the stylesheet will be the
1366                     // first one in the array.
1367                     bestMatchedPattern = conflicts[0];
1368 
1369                     bestMatchedRule = bestMatchedPattern->getTemplate();
1370 
1371                     const StylesheetExecutionContext::GetCachedString   theGuard(executionContext);
1372 
1373                     executionContext.problem(
1374                         StylesheetExecutionContext::eXSLTProcessor,
1375                         StylesheetExecutionContext::eWarning,
1376                         XalanMessageLoader::getMessage(
1377                             theGuard.get(),
1378                             XalanMessages::ConflictsFound),
1379                         bestMatchedRule->getLocator(),
1380                         targetNode);
1381                 }
1382             }
1383 
1384             if (0 == bestMatchedRule)
1385             {
1386                 bestMatchedRule = findTemplateInImports(executionContext, targetNode, targetNodeType, mode);
1387             }
1388         }
1389 
1390         return bestMatchedRule;
1391     }
1392 }
1393 
1394 
1395 
1396 void
processExtensionNamespace(StylesheetConstructionContext & theConstructionContext,const XalanDOMString & uri)1397 Stylesheet::processExtensionNamespace(
1398             StylesheetConstructionContext&  theConstructionContext,
1399             const XalanDOMString&           uri)
1400 {
1401     XalanMemMgrAutoPtr<ExtensionNSHandler>  theGuard(
1402                                                 theConstructionContext.getMemoryManager(),
1403                                                 ExtensionNSHandler::create(
1404                                                     uri,
1405                                                     theConstructionContext.getMemoryManager()));
1406 
1407     m_extensionNamespaces.insert(uri, theGuard.get());
1408 
1409     theGuard.release();
1410 
1411     m_namespacesHandler.addExtensionNamespaceURI(theConstructionContext, uri);
1412 }
1413 
1414 
1415 
1416 void
pushTopLevelVariables(StylesheetExecutionContext & executionContext,const ParamVectorType & topLevelParams) const1417 Stylesheet::pushTopLevelVariables(
1418             StylesheetExecutionContext&     executionContext,
1419             const ParamVectorType&          topLevelParams) const
1420 {
1421     {
1422         // First, push any imports...
1423         const StylesheetVectorType::const_reverse_iterator  rend = m_imports.rend();
1424 
1425         for (StylesheetVectorType::const_reverse_iterator i = m_imports.rbegin(); i != rend; ++i)
1426         {
1427             const Stylesheet* const stylesheet = *i;
1428             assert(stylesheet != 0);
1429 
1430             stylesheet->pushTopLevelVariables(executionContext, topLevelParams);
1431         }
1432     }
1433 
1434     const ParamVectorType::size_type    nVars = m_topLevelVariables.size();
1435 
1436     for (ParamVectorType::size_type i = 0; i < nVars; ++i)
1437     {
1438         ElemVariable* const     var = m_topLevelVariables[i];
1439 
1440         bool                    isParam =
1441                 StylesheetConstructionContext::ELEMNAME_PARAM == var->getXSLToken();
1442 
1443         if(isParam == true)
1444         {
1445             isParam = false;
1446 
1447             const ParamVectorType::size_type    n = topLevelParams.size();
1448 
1449             for(ParamVectorType::size_type k = 0; k < n; k++)
1450             {
1451                 const ParamVectorType::value_type&  arg = topLevelParams[k];
1452 
1453                 if(arg.getName().equals(var->getNameAttribute()))
1454                 {
1455                     isParam = true;
1456 
1457                     if (arg.getXObject().null() == false)
1458                     {
1459                         executionContext.pushVariable(
1460                             arg.getName(),
1461                             arg.getXObject(),
1462                             0);
1463                     }
1464                     else
1465                     {
1466                         executionContext.pushVariable(
1467                             arg.getName(),
1468                             0,
1469                             arg.getExpression(),
1470                             executionContext.getRootDocument(),
1471                             *this);
1472                     }
1473 
1474                     break;
1475                 }
1476             }
1477         }
1478 
1479         if (isParam == false)
1480         {
1481             executionContext.pushVariable(var->getNameAttribute(),
1482                                           var,
1483                                           var->getParentNodeElem());
1484         }
1485     }
1486 }
1487 
1488 
1489 
1490 void
processNSAliasElement(const XalanDOMChar * name,const AttributeListType & atts,StylesheetConstructionContext & constructionContext)1491 Stylesheet::processNSAliasElement(
1492             const XalanDOMChar*             name,
1493             const AttributeListType&        atts,
1494             StylesheetConstructionContext&  constructionContext)
1495 {
1496     const XalanSize_t       nAttrs = atts.getLength();
1497 
1498     const XalanDOMString*   stylesheetNamespace = 0;
1499     const XalanDOMString*   resultNamespace = 0;
1500 
1501     for (XalanSize_t i = 0; i < nAttrs; i++)
1502     {
1503         const XalanDOMChar* const   aname = atts.getName(i);
1504 
1505         if (aname == Constants::ATTRNAME_STYLESHEET_PREFIX)
1506         {
1507             const XalanDOMChar* const   value = atts.getValue(i);
1508 
1509             if (equals(value, Constants::ATTRVAL_DEFAULT_PREFIX) == true)
1510             {
1511                 stylesheetNamespace =
1512                     getNamespaceForPrefix(
1513                         DOMServices::s_emptyString,
1514                         constructionContext);
1515             }
1516             else
1517             {
1518                 stylesheetNamespace =
1519                     getNamespaceForPrefix(
1520                         value,
1521                         constructionContext);
1522             }
1523         }
1524         else if (aname == Constants::ATTRNAME_RESULT_PREFIX)
1525         {
1526             const XalanDOMChar* const   value = atts.getValue(i);
1527 
1528             if (equals(value, Constants::ATTRVAL_DEFAULT_PREFIX) == true)
1529             {
1530                 resultNamespace =
1531                     getNamespaceForPrefix(
1532                         DOMServices::s_emptyString,
1533                         constructionContext);
1534             }
1535             else
1536             {
1537                 resultNamespace =
1538                     getNamespaceForPrefix(
1539                         value,
1540                         constructionContext);
1541             }
1542         }
1543         else if (!isAttrOK(aname, atts, i, constructionContext))
1544         {
1545             error(
1546                 constructionContext,
1547                 XalanMessages::ElementHasIllegalAttribute_2Param,
1548                 constructionContext.getLocatorFromStack(),
1549                 name,
1550                 aname);
1551         }
1552     }
1553 
1554     // Build a table of aliases, the key is the stylesheet uri and the
1555     // value is the result uri
1556     if (stylesheetNamespace == 0)
1557     {
1558         error(
1559             constructionContext,
1560             XalanMessages::ElementMustHaveAttribute_2Param,
1561             constructionContext.getLocatorFromStack(),
1562             name,
1563             Constants::ATTRNAME_STYLESHEET_PREFIX.c_str());
1564     }
1565     else if (resultNamespace == 0)
1566     {
1567         error(
1568             constructionContext,
1569             XalanMessages::ElementMustHaveAttribute_2Param,
1570             constructionContext.getLocatorFromStack(),
1571             name,
1572             Constants::ATTRNAME_RESULT_PREFIX.c_str());
1573     }
1574     else
1575     {
1576         assert(stylesheetNamespace->empty() == false && resultNamespace->empty() == false);
1577 
1578         m_namespacesHandler.setNamespaceAlias(
1579                 constructionContext,
1580                 *stylesheetNamespace,
1581                 *resultNamespace);
1582     }
1583 }
1584 
1585 
1586 
1587 void
processDecimalFormatElement(StylesheetConstructionContext & constructionContext,const AttributeListType & atts,const Locator * locator)1588 Stylesheet::processDecimalFormatElement(
1589             StylesheetConstructionContext&  constructionContext,
1590             const AttributeListType&        atts,
1591             const Locator*                  locator)
1592 {
1593     const XalanFileLoc  lineNumber =
1594         XalanLocator::getLineNumber(locator);
1595 
1596     const XalanFileLoc  columnNumber =
1597         XalanLocator::getColumnNumber(locator);
1598 
1599     m_elemDecimalFormats.reserve(m_elemDecimalFormats.size() + 1);
1600 
1601     ElemDecimalFormat*  theInstance;
1602 
1603     XalanConstruct(
1604         constructionContext.getMemoryManager(),
1605         theInstance,
1606         constructionContext,
1607         *this,
1608         atts,
1609         lineNumber,
1610         columnNumber);
1611 
1612     m_elemDecimalFormats.push_back(theInstance);
1613 }
1614 
1615 
1616 
1617 const XalanDecimalFormatSymbols*
getDecimalFormatSymbols(const XalanQName & theQName) const1618 Stylesheet::getDecimalFormatSymbols(const XalanQName&   theQName) const
1619 {
1620     const XalanDecimalFormatSymbols*                dfs = 0;
1621 
1622     const ElemDecimalFormatVectorType::size_type    theSize =
1623         m_elemDecimalFormats.size();
1624 
1625     if (theSize > 0)
1626     {
1627         // Start from the top of the stack
1628         for (ElemDecimalFormatVectorType::size_type i = theSize; i > 0; --i)
1629         {
1630             assert(m_elemDecimalFormats[i - 1] != 0);
1631 
1632             const ElemDecimalFormat* const  theCurrent =
1633                 m_elemDecimalFormats[i - 1];
1634             assert(theCurrent != 0);
1635 
1636             if (theCurrent->getQName().equals(theQName) == true)
1637             {
1638                 dfs = &theCurrent->getDecimalFormatSymbols();
1639 
1640                 break;
1641             }
1642         }
1643     }
1644 
1645     // If dfs is null at this point, it should
1646     // mean there wasn't an xsl:decimal-format declared
1647     // with the given name. So go up the import hierarchy
1648     // and see if one of the imported stylesheets declared
1649     // it.
1650     if (dfs == 0)
1651     {
1652         for (StylesheetVectorType::size_type i = 0; i < m_importsSize; ++i)
1653         {
1654             dfs = m_imports[i]->getDecimalFormatSymbols(theQName);
1655 
1656             if (dfs != 0)
1657             {
1658                 break;
1659             }
1660         }
1661     }
1662 
1663     return dfs;
1664 }
1665 
1666 
1667 
1668 const XalanDOMString*
getNamespaceForPrefix(const XalanDOMString & prefix) const1669 Stylesheet::getNamespaceForPrefix(const XalanDOMString&     prefix) const
1670 {
1671     return XalanQName::getNamespaceForPrefix(m_namespaceDecls, prefix);
1672 }
1673 
1674 
1675 
1676 const XalanDOMString&
getURI() const1677 Stylesheet::getURI() const
1678 {
1679     return m_baseIdent;
1680 }
1681 
1682 
1683 
1684 }
1685