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