| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * |
| * Copyright (c) 1999 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, |
| * if any, must include the following acknowledgment: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowledgment may appear in the software itself, |
| * if and wherever such third-party acknowledgments normally appear. |
| * |
| * 4. The names "Xalan" and "Apache Software Foundation" must |
| * not be used to endorse or promote products derived from this |
| * software without prior written permission. For written |
| * permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache", |
| * nor may "Apache" appear in their name, without prior written |
| * permission of the Apache Software Foundation. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation and was |
| * originally based on software copyright (c) 1999, International |
| * Business Machines, Inc., http://www.ibm.com. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| #include "StylesheetHandler.hpp" |
| |
| |
| |
| #include <algorithm> |
| |
| |
| |
| #include <sax/Locator.hpp> |
| #include <sax/SAXParseException.hpp> |
| #include <util/XMLURL.hpp> |
| |
| |
| |
| #include <Include/STLHelper.hpp> |
| |
| |
| |
| #include <XalanDOM/XalanDOMException.hpp> |
| |
| |
| |
| #include <PlatformSupport/AttributeListImpl.hpp> |
| #include <PlatformSupport/DOMStringHelper.hpp> |
| #include <PlatformSupport/DoubleSupport.hpp> |
| #include <PlatformSupport/StringTokenizer.hpp> |
| |
| |
| |
| #include <DOMSupport/DOMServices.hpp> |
| |
| |
| |
| #include "Constants.hpp" |
| #include "ElemApplyImport.hpp" |
| #include "ElemApplyTemplates.hpp" |
| #include "ElemAttribute.hpp" |
| #include "ElemAttributeSet.hpp" |
| #include "ElemCallTemplate.hpp" |
| #include "ElemChoose.hpp" |
| #include "ElemComment.hpp" |
| #include "ElemCopy.hpp" |
| #include "ElemCopyOf.hpp" |
| #include "ElemDecimalFormat.hpp" |
| #include "ElemElement.hpp" |
| #include "ElemEmpty.hpp" |
| #include "ElemExtensionCall.hpp" |
| #include "ElemFallback.hpp" |
| #include "ElemForEach.hpp" |
| #include "ElemIf.hpp" |
| #include "ElemLiteralResult.hpp" |
| #include "ElemMessage.hpp" |
| #include "ElemNumber.hpp" |
| #include "ElemOtherwise.hpp" |
| #include "ElemParam.hpp" |
| #include "ElemPI.hpp" |
| #include "ElemSort.hpp" |
| #include "ElemTemplate.hpp" |
| #include "ElemText.hpp" |
| #include "ElemTextLiteral.hpp" |
| #include "ElemUse.hpp" |
| #include "ElemValueOf.hpp" |
| #include "ElemWhen.hpp" |
| #include "ElemWithParam.hpp" |
| #include "ExtensionNSHandler.hpp" |
| #include "Stylesheet.hpp" |
| #include "StylesheetConstructionContext.hpp" |
| #include "StylesheetRoot.hpp" |
| |
| |
| |
| #include <Include/XalanAutoPtr.hpp> |
| |
| |
| |
| StylesheetHandler::StylesheetHandler( |
| Stylesheet& stylesheetTree, |
| StylesheetConstructionContext& constructionContext) : |
| FormatterListener(OUTPUT_METHOD_OTHER), |
| m_stylesheet(stylesheetTree), |
| m_constructionContext(constructionContext), |
| m_elemStack(), |
| m_elemStackParentedElements(), |
| m_strayElements(), |
| m_whiteSpaceElems(), |
| m_pTemplate(0), |
| m_lastPopped(0), |
| m_inTemplate(false), |
| m_foundStylesheet(false), |
| m_foundNotImport(false), |
| m_accumulateText(), |
| m_includeBase(stylesheetTree.getBaseIdentifier()), |
| m_inExtensionElementStack(), |
| m_inLXSLTScript(false), |
| m_LXSLTScriptBody(), |
| m_LXSLTScriptLang(), |
| m_LXSLTScriptSrcURL(), |
| m_pLXSLTExtensionNSH(0), |
| m_locatorsPushed(0) |
| { |
| } |
| |
| |
| |
| StylesheetHandler::~StylesheetHandler() |
| { |
| #if !defined(XALAN_NO_NAMESPACES) |
| using std::for_each; |
| #endif |
| |
| // Clean up the element stack vector... |
| ElemTemplateStackType::const_iterator i = m_elemStack.begin(); |
| |
| while(i != m_elemStack.end()) |
| { |
| // See if the element is in the set of elements that have |
| // already been parented, so we don't try to delete it after |
| // it's parent has already deleted it... |
| const ElemTemplateSetType::iterator j = |
| m_elemStackParentedElements.find(*i); |
| |
| if (j == m_elemStackParentedElements.end()) |
| { |
| // Not found, so delete it... |
| delete *i; |
| } |
| else |
| { |
| // Found, so erase it from the set... |
| m_elemStackParentedElements.erase(j); |
| } |
| |
| ++i; |
| } |
| |
| doCleanup(); |
| |
| // Clean up the whitespace elements. |
| for_each(m_whiteSpaceElems.begin(), |
| m_whiteSpaceElems.end(), |
| DeleteFunctor<ElemTextLiteral>()); |
| |
| // Clean up the stray elements. |
| for_each(m_strayElements.begin(), |
| m_strayElements.end(), |
| DeleteFunctor<ElemTemplateElement>()); |
| |
| m_elemStackParentedElements.clear(); |
| } |
| |
| |
| |
| void StylesheetHandler::setDocumentLocator(const Locator* const locator) |
| { |
| m_constructionContext.pushLocatorOnStack(locator); |
| |
| ++m_locatorsPushed; |
| } |
| |
| |
| void StylesheetHandler::startDocument() |
| { |
| } |
| |
| |
| void StylesheetHandler::endDocument() |
| { |
| m_constructionContext.popLocatorStack(); |
| |
| if (m_locatorsPushed > 0) |
| { |
| --m_locatorsPushed; |
| } |
| |
| m_inExtensionElementStack.clear(); |
| } |
| |
| |
| |
| bool |
| StylesheetHandler::isAttrOK( |
| const XalanDOMChar* attrName, |
| const AttributeList& atts, |
| int which) |
| { |
| return m_stylesheet.isAttrOK(attrName, atts, which, m_constructionContext); |
| } |
| |
| |
| |
| bool |
| StylesheetHandler::processSpaceAttr( |
| const XalanDOMChar* aname, |
| const AttributeList& atts, |
| int which, |
| const Locator* locator, |
| bool& fPreserve) |
| { |
| const XalanDOMString theAttributeName(aname); |
| |
| const XalanQNameByValue theName(theAttributeName, m_stylesheet.getNamespaces()); |
| |
| const bool isSpaceAttr = s_spaceAttrQName.equals(theName); |
| |
| if(isSpaceAttr == false) |
| { |
| fPreserve = false; |
| } |
| else |
| { |
| const XalanDOMChar* const spaceVal = atts.getValue(which); |
| |
| if(equals(spaceVal, Constants::ATTRVAL_DEFAULT)) |
| { |
| fPreserve = false; |
| } |
| else if(equals(spaceVal, Constants::ATTRVAL_PRESERVE)) |
| { |
| fPreserve = true; |
| } |
| else |
| { |
| error("xml:space has an illegal value", locator); |
| } |
| } |
| |
| return isSpaceAttr; |
| } |
| |
| |
| |
| inline int |
| getLineNumber(const Locator* theLocator) |
| { |
| return theLocator == 0 ? -1 : theLocator->getLineNumber(); |
| } |
| |
| |
| |
| inline int |
| getColumnNumber(const Locator* theLocator) |
| { |
| return theLocator == 0 ? -1 : theLocator->getColumnNumber(); |
| } |
| |
| |
| |
| bool |
| StylesheetHandler::processSpaceAttr( |
| const AttributeList& atts, |
| const Locator* locator, |
| bool& fPreserve) |
| { |
| const unsigned int len = atts.getLength(); |
| |
| for (unsigned int i = 0; i < len; ++i) |
| { |
| if (processSpaceAttr(atts.getName(i), atts, i, locator, fPreserve) == true) |
| { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| |
| |
| void |
| StylesheetHandler::startElement( |
| const XMLCh* const name, |
| AttributeList& atts) |
| { |
| m_inExtensionElementStack.push_back(false); |
| |
| if (m_preserveSpaceStack.empty() == true) |
| { |
| m_preserveSpaceStack.push_back(false); |
| } |
| else |
| { |
| m_preserveSpaceStack.push_back(m_preserveSpaceStack.back()); |
| } |
| |
| try |
| { |
| #if !defined(XALAN_NO_NAMESPACES) |
| using std::for_each; |
| #endif |
| |
| // By default, space is not preserved... |
| bool fPreserveSpace = false; |
| bool fSpaceAttrProcessed = false; |
| |
| processAccumulatedText(); |
| |
| // Clean up the whitespace elements. |
| for_each(m_whiteSpaceElems.begin(), |
| m_whiteSpaceElems.end(), |
| DeleteFunctor<ElemTextLiteral>()); |
| |
| m_whiteSpaceElems.clear(); |
| |
| const Locator* const locator = m_constructionContext.getLocatorFromStack(); |
| |
| const int lineNumber = getLineNumber(locator); |
| const int columnNumber = getColumnNumber(locator); |
| |
| // First push namespaces |
| m_stylesheet.pushNamespaces(atts); |
| |
| const XalanDOMString& ns = getNamespaceFromStack(name); |
| |
| const XalanDOMString::size_type nameLength = length(name); |
| const XalanDOMString::size_type index = indexOf(name, XalanUnicode::charColon); |
| |
| const XalanDOMString localName = index == nameLength ? XalanDOMString(name) : substring(name, index + 1); |
| |
| if(length(ns) == 0 && nameLength != length(localName)) |
| { |
| // Warn that there is a prefix that was not resolved... |
| m_constructionContext.warn("Could not resolve prefix " + XalanDOMString(name)); |
| } |
| |
| ElemTemplateElement* elem = 0; |
| |
| const ElemTemplateStackType::size_type origStackSize = m_elemStack.size(); |
| |
| if(equals(ns, m_constructionContext.getXSLTNamespaceURI())) |
| { |
| if(!isEmpty(m_stylesheet.getXSLTNamespaceURI())) |
| m_stylesheet.setXSLTNamespaceURI(ns); |
| |
| if(false == m_foundStylesheet) |
| { |
| m_stylesheet.getStylesheetRoot().initDefaultRule(m_constructionContext); |
| m_stylesheet.setWrapperless(false); |
| } |
| |
| const int xslToken = m_constructionContext.getElementToken(localName); |
| |
| if(!m_inTemplate) |
| { |
| processTopLevelElement(name, localName, ns, atts, xslToken, locator, fPreserveSpace, fSpaceAttrProcessed); |
| } |
| else |
| { |
| switch(xslToken) |
| { |
| case Constants::ELEMNAME_APPLY_TEMPLATES: |
| elem = new ElemApplyTemplates(m_constructionContext, |
| m_stylesheet, |
| atts, lineNumber, columnNumber); |
| break; |
| |
| case Constants::ELEMNAME_CALLTEMPLATE: |
| elem = new ElemCallTemplate(m_constructionContext, |
| m_stylesheet, |
| atts, lineNumber, columnNumber); |
| break; |
| |
| case Constants::ELEMNAME_WITHPARAM: |
| elem = new ElemWithParam(m_constructionContext, |
| m_stylesheet, |
| atts, lineNumber, columnNumber); |
| break; |
| |
| case Constants::ELEMNAME_FOREACH: |
| elem = new ElemForEach(m_constructionContext, |
| m_stylesheet, |
| atts, lineNumber, columnNumber); |
| break; |
| |
| case Constants::ELEMNAME_SORT: |
| { |
| if (m_elemStack.empty() == true) |
| { |
| error("Misplaced xsl:sort.", locator); |
| } |
| |
| ElemTemplateElement* const theElement = |
| m_elemStack.back(); |
| assert(theElement != 0); |
| |
| const int xslToken = theElement->getXSLToken(); |
| |
| if (xslToken != Constants::ELEMNAME_FOREACH && |
| xslToken != Constants::ELEMNAME_APPLY_TEMPLATES) |
| { |
| error("Misplaced xsl:sort.", locator); |
| } |
| |
| ElemForEach* foreach = |
| #if defined(XALAN_OLD_STYLE_CASTS) |
| (ElemForEach*)theElement; |
| #else |
| static_cast<ElemForEach*>(theElement); |
| #endif |
| |
| ElemSort* sortElem = new ElemSort(m_constructionContext, |
| m_stylesheet, |
| atts, lineNumber, columnNumber); |
| |
| // Note: deleted in ElemForEach destructor |
| foreach->getSortElems().push_back(sortElem); |
| |
| sortElem->setParentNodeElem(foreach); |
| |
| m_elemStackParentedElements.insert(foreach); |
| } |
| break; |
| |
| case Constants::ELEMNAME_APPLY_IMPORTS: |
| { |
| if (m_elemStack.empty() == true) |
| { |
| error("xsl:apply-imports is not allowed at this position in the stylesheet", locator); |
| } |
| |
| ElemTemplateElement* const theElement = |
| m_elemStack.back(); |
| assert(theElement != 0); |
| |
| const int xslToken = theElement->getXSLToken(); |
| |
| if (xslToken == Constants::ELEMNAME_FOREACH) |
| { |
| error("xsl:apply-imports is not allowed at this position in the stylesheet", locator); |
| } |
| |
| elem = new ElemApplyImport(m_constructionContext, |
| m_stylesheet, |
| atts, lineNumber, columnNumber); |
| } |
| break; |
| |
| case Constants::ELEMNAME_VALUEOF: |
| elem = new ElemValueOf(m_constructionContext, |
| m_stylesheet, |
| atts, lineNumber, columnNumber); |
| break; |
| |
| case Constants::ELEMNAME_NUMBER: |
| elem = new ElemNumber(m_constructionContext, |
| m_stylesheet, |
| atts, lineNumber, columnNumber); |
| break; |
| |
| case Constants::ELEMNAME_VARIABLE: |
| elem = new ElemVariable(m_constructionContext, |
| m_stylesheet, |
| atts, lineNumber, columnNumber); |
| break; |
| |
| case Constants::ELEMNAME_PARAMVARIABLE: |
| elem = new ElemParam(m_constructionContext, |
| m_stylesheet, |
| atts, lineNumber, columnNumber); |
| break; |
| |
| case Constants::ELEMNAME_IF: |
| elem = new ElemIf(m_constructionContext, |
| m_stylesheet, |
| atts, lineNumber, columnNumber); |
| break; |
| |
| case Constants::ELEMNAME_FALLBACK: |
| elem = new ElemFallback( |
| m_constructionContext, |
| m_stylesheet, |
| atts, |
| lineNumber, |
| columnNumber); |
| break; |
| |
| case Constants::ELEMNAME_CHOOSE: |
| elem = new ElemChoose(m_constructionContext, |
| m_stylesheet, |
| atts, lineNumber, columnNumber); |
| break; |
| |
| case Constants::ELEMNAME_WHEN: |
| { |
| ElemTemplateElement* const parent = m_elemStack.back(); |
| |
| if(Constants::ELEMNAME_CHOOSE == parent->getXSLToken()) |
| { |
| ElemTemplateElement* const lastChild = parent->getLastChildElem(); |
| |
| if(0 == lastChild || |
| Constants::ELEMNAME_WHEN == lastChild->getXSLToken() || |
| lastChild->isWhitespace() == true) |
| { |
| elem = new ElemWhen(m_constructionContext, |
| m_stylesheet, |
| atts, lineNumber, columnNumber); |
| } |
| else |
| { |
| error("(StylesheetHandler) misplaced xsl:when.", locator); |
| } |
| } |
| else |
| { |
| error("(StylesheetHandler) xsl:when not parented by xsl:choose.", locator); |
| } |
| } |
| break; |
| |
| case Constants::ELEMNAME_OTHERWISE: |
| { |
| ElemTemplateElement* parent = m_elemStack.back(); |
| |
| if(Constants::ELEMNAME_CHOOSE == parent->getXSLToken()) |
| { |
| ElemTemplateElement* lastChild = parent->getLastChildElem(); |
| |
| if(0 == lastChild || |
| Constants::ELEMNAME_WHEN == lastChild->getXSLToken() || |
| lastChild->isWhitespace() == true) |
| { |
| elem = new ElemOtherwise(m_constructionContext, |
| m_stylesheet, |
| atts, lineNumber, columnNumber); |
| } |
| else |
| { |
| error("Misplaced xsl:otherwise.", locator); |
| } |
| } |
| else |
| { |
| error("xsl:otherwise not parented by xsl:choose.", locator); |
| } |
| } |
| break; |
| |
| case Constants::ELEMNAME_COPY_OF: |
| elem = new ElemCopyOf(m_constructionContext, |
| m_stylesheet, |
| atts, lineNumber, columnNumber); |
| break; |
| |
| case Constants::ELEMNAME_COPY: |
| elem = new ElemCopy(m_constructionContext, |
| m_stylesheet, |
| atts, lineNumber, columnNumber); |
| break; |
| |
| case Constants::ELEMNAME_TEXT: |
| // Just push the element on the stack to signal |
| // that space should be preserved. |
| m_elemStack.push_back(new ElemText(m_constructionContext, |
| m_stylesheet, |
| atts, lineNumber, columnNumber)); |
| break; |
| |
| case Constants::ELEMNAME_USE: |
| elem = new ElemUse(m_constructionContext, |
| m_stylesheet, |
| lineNumber, columnNumber); |
| break; |
| |
| case Constants::ELEMNAME_ATTRIBUTE: |
| elem = new ElemAttribute(m_constructionContext, |
| m_stylesheet, |
| atts, lineNumber, columnNumber); |
| break; |
| |
| case Constants::ELEMNAME_ELEMENT: |
| elem = new ElemElement(m_constructionContext, |
| m_stylesheet, |
| atts, lineNumber, columnNumber); |
| break; |
| |
| case Constants::ELEMNAME_PI: |
| elem = new ElemPI(m_constructionContext, |
| m_stylesheet, |
| atts, lineNumber, columnNumber); |
| break; |
| |
| case Constants::ELEMNAME_COMMENT: |
| elem = new ElemComment(m_constructionContext, |
| m_stylesheet, |
| atts, lineNumber, columnNumber); |
| break; |
| |
| case Constants::ELEMNAME_MESSAGE: |
| elem = new ElemMessage(m_constructionContext, |
| m_stylesheet, |
| atts, lineNumber, columnNumber); |
| |
| break; |
| |
| case Constants::ELEMNAME_TEMPLATE: |
| case Constants::ELEMNAME_LOCALE: |
| case Constants::ELEMNAME_DEFINEATTRIBUTESET: |
| case Constants::ELEMNAME_DEFINESCRIPT: |
| case Constants::ELEMNAME_EXTENSION: |
| case Constants::ELEMNAME_EXTENSIONHANDLER: |
| case Constants::ELEMNAME_KEY: |
| case Constants::ELEMNAME_IMPORT: |
| case Constants::ELEMNAME_INCLUDE: |
| case Constants::ELEMNAME_PRESERVESPACE: |
| case Constants::ELEMNAME_STRIPSPACE: |
| { |
| const XalanDOMString msg(XalanDOMString(name) + " is not allowed inside a template."); |
| |
| error(msg, locator); |
| } |
| break; |
| |
| default: |
| { |
| const XalanDOMString msg("Unknown XSL element: " + localName); |
| |
| // If this stylesheet is declared to be of a higher version than the one |
| // supported, don't flag an error. |
| if(m_constructionContext.getXSLTVersionSupported() < m_stylesheet.getXSLTVerDeclared()) |
| { |
| m_constructionContext.warn(msg); |
| } |
| else |
| { |
| error(msg, locator); |
| } |
| } |
| } |
| } |
| } |
| else if (!m_inTemplate && startsWith(ns, m_constructionContext.getXalanXSLNameSpaceURL())) |
| { |
| processExtensionElement(name, localName, atts, locator); |
| } |
| else |
| { |
| if(!m_inTemplate && !m_foundStylesheet) |
| { |
| elem = initWrapperless(name, atts, lineNumber, columnNumber); |
| } |
| else |
| { |
| // BEGIN SANJIVA CODE |
| // is this an extension element call? |
| ExtensionNSHandler* nsh = 0; |
| |
| if (!isEmpty(ns) && |
| ((nsh = m_stylesheet.lookupExtensionNSHandler(ns)) != 0)) |
| { |
| elem = new ElemExtensionCall (m_constructionContext, |
| m_stylesheet, |
| name, |
| atts, |
| lineNumber, |
| columnNumber, |
| *nsh, |
| localName); |
| |
| assert(m_inExtensionElementStack.empty() == false); |
| |
| m_inExtensionElementStack.back() = true; |
| } |
| else |
| { |
| elem = new ElemLiteralResult(m_constructionContext, |
| m_stylesheet, |
| name, |
| atts, |
| lineNumber, |
| columnNumber); |
| } |
| } |
| } |
| |
| if(m_inTemplate && 0 != elem) |
| { |
| if(!m_elemStack.empty()) |
| { |
| // Guard against an exception in appendChildElem()... |
| XalanAutoPtr<ElemTemplateElement> theGuard(elem); |
| |
| appendChildElementToParent(elem, locator); |
| |
| // The element is parented and will now be |
| // deleted when the parent is delete... |
| theGuard.release(); |
| } |
| |
| m_elemStack.push_back(elem); |
| } |
| |
| // If we haven't processed an xml:space attribute already, look for one... |
| if (fSpaceAttrProcessed == false) |
| { |
| fSpaceAttrProcessed = processSpaceAttr(atts, locator, fPreserveSpace); |
| } |
| |
| // Only update the stack if we actually processed an xml:space attribute... |
| if (fSpaceAttrProcessed == true) |
| { |
| // Set the preserve value... |
| m_preserveSpaceStack.back() = fPreserveSpace; |
| } |
| |
| // If for some reason something didn't get pushed, push an empty |
| // object. |
| if(origStackSize == m_elemStack.size()) |
| { |
| m_elemStack.push_back(new ElemEmpty(m_constructionContext, |
| m_stylesheet, |
| lineNumber, columnNumber)); |
| |
| if (elem != 0) |
| { |
| delete elem; |
| |
| m_elemStackParentedElements.erase(elem); |
| } |
| } |
| } // end try |
| catch(...) |
| { |
| doCleanup(); |
| |
| throw; |
| } |
| } |
| |
| |
| |
| ElemTemplateElement* |
| StylesheetHandler::initWrapperless( |
| const XalanDOMChar* name, |
| const AttributeList& atts, |
| int lineNumber, |
| int columnNumber) |
| { |
| m_stylesheet.getStylesheetRoot().initDefaultRule(m_constructionContext); |
| |
| AttributeListImpl templateAttrs; |
| |
| templateAttrs.addAttribute(c_wstr(Constants::ATTRNAME_NAME), |
| c_wstr(Constants::ATTRTYPE_CDATA), |
| c_wstr(Constants::ATTRVAL_SIMPLE)); |
| |
| m_pTemplate = new ElemTemplate(m_constructionContext, |
| m_stylesheet, |
| templateAttrs, |
| lineNumber, |
| columnNumber); |
| |
| ElemTemplateElement* const pElem = |
| new ElemLiteralResult(m_constructionContext, |
| m_stylesheet, |
| name, |
| atts, |
| lineNumber, |
| columnNumber); |
| |
| m_pTemplate->appendChildElem(pElem); |
| m_inTemplate = true; |
| |
| m_stylesheet.setWrapperlessTemplate(m_pTemplate); |
| |
| m_foundStylesheet = true; |
| m_stylesheet.setWrapperless(true); |
| |
| // This attempts to optimize for a literal result element with |
| // the name HTML, so we don't have to switch on-the-fly. |
| if(equalsIgnoreCaseASCII(name, Constants::ELEMNAME_HTML_STRING) == true) |
| { |
| // If there's a default namespace, then we must output XML. |
| // Otherwise, we'll set the output method to HTML. |
| if (atts.getValue(c_wstr(DOMServices::s_XMLNamespace)) == 0) |
| { |
| m_stylesheet.getStylesheetRoot().setIndentResult(true); |
| m_stylesheet.getStylesheetRoot().setOutputMethod(OUTPUT_METHOD_HTML); |
| } |
| } |
| |
| return pElem; |
| } |
| |
| |
| |
| const XalanDOMString& |
| StylesheetHandler::getNamespaceFromStack(const XalanDOMChar* theName) const |
| { |
| const XalanDOMString* const theNamespace = |
| m_stylesheet.getNamespaceFromStack(theName); |
| |
| if (theNamespace == 0) |
| { |
| return s_emptyString; |
| } |
| else |
| { |
| return *theNamespace; |
| } |
| } |
| |
| |
| |
| const XalanDOMString& |
| StylesheetHandler::getNamespaceForPrefixFromStack(const XalanDOMString& thePrefix) const |
| { |
| const XalanDOMString* const theNamespace = |
| m_stylesheet.getNamespaceForPrefixFromStack(thePrefix); |
| |
| if (theNamespace == 0) |
| { |
| return s_emptyString; |
| } |
| else |
| { |
| return *theNamespace; |
| } |
| } |
| |
| |
| |
| void |
| StylesheetHandler::processTopLevelElement( |
| const XalanDOMChar* name, |
| const XalanDOMString& localName, |
| const XalanDOMString& ns, |
| const AttributeList& atts, |
| int xslToken, |
| const Locator* locator, |
| bool& fPreserveSpace, |
| bool& fSpaceAttrProcessed) |
| { |
| if(m_foundStylesheet && Constants::ELEMNAME_IMPORT != xslToken) |
| { |
| m_foundNotImport = true; |
| } |
| |
| const int lineNumber = getLineNumber(locator); |
| const int columnNumber = getColumnNumber(locator); |
| |
| switch(xslToken) |
| { |
| case Constants::ELEMNAME_TEMPLATE: |
| m_pTemplate = new ElemTemplate( |
| m_constructionContext, |
| m_stylesheet, |
| atts, |
| lineNumber, |
| columnNumber); |
| |
| m_elemStack.push_back(m_pTemplate); |
| m_elemStackParentedElements.insert(m_pTemplate); |
| m_inTemplate = true; |
| m_stylesheet.addTemplate(m_pTemplate, m_constructionContext); |
| break; |
| |
| case Constants::ELEMNAME_EXTENSION: |
| if(!equalsIgnoreCaseASCII(ns, m_constructionContext.getXalanXSLNameSpaceURL())) |
| { |
| m_constructionContext.warn("Old syntax: the functions instruction should use a url of " + m_constructionContext.getXalanXSLNameSpaceURL()); |
| } |
| break; |
| |
| case Constants::ELEMNAME_VARIABLE: |
| case Constants::ELEMNAME_PARAMVARIABLE: |
| { |
| ElemVariable* varelem = (Constants::ELEMNAME_PARAMVARIABLE == xslToken) |
| ? new ElemParam(m_constructionContext, |
| m_stylesheet, |
| atts, |
| lineNumber, columnNumber) |
| : new ElemVariable(m_constructionContext, |
| m_stylesheet, |
| atts, |
| lineNumber, columnNumber); |
| |
| m_elemStack.push_back(varelem); |
| m_inTemplate = true; // fake it out |
| m_stylesheet.setTopLevelVariable(varelem); |
| m_elemStackParentedElements.insert(varelem); |
| varelem->setTopLevel(true); |
| } |
| break; |
| |
| case Constants::ELEMNAME_LOCALE: |
| m_constructionContext.warn(StaticStringToDOMString(XALAN_STATIC_UCODE_STRING("xsl:locale not yet supported."))); |
| break; |
| |
| case Constants::ELEMNAME_PRESERVESPACE: |
| case Constants::ELEMNAME_STRIPSPACE: |
| processPreserveStripSpace(name, atts, locator, xslToken); |
| break; |
| |
| case Constants::ELEMNAME_KEY: |
| { |
| ElemEmpty nsContext(m_constructionContext, m_stylesheet, lineNumber, columnNumber); |
| |
| m_stylesheet.processKeyElement(&nsContext, atts, m_constructionContext); |
| } |
| break; |
| |
| case Constants::ELEMNAME_DEFINEATTRIBUTESET: |
| { |
| m_inTemplate = true; // fake it out |
| |
| ElemAttributeSet* attrSet = new ElemAttributeSet(m_constructionContext, |
| m_stylesheet, |
| atts, |
| lineNumber, |
| columnNumber); |
| |
| m_elemStack.push_back(attrSet); |
| } |
| break; |
| |
| case Constants::ELEMNAME_INCLUDE: |
| processInclude(name, atts, locator); |
| break; |
| |
| case Constants::ELEMNAME_IMPORT: |
| processImport(name, atts, locator); |
| break; |
| |
| case Constants::ELEMNAME_OUTPUT: |
| m_stylesheet.getStylesheetRoot().processOutputSpec(name, atts, m_constructionContext); |
| break; |
| |
| case Constants::ELEMNAME_DECIMALFORMAT: |
| m_stylesheet.processDecimalFormatElement( |
| new ElemDecimalFormat( |
| m_constructionContext, |
| m_stylesheet, |
| atts, |
| lineNumber, |
| columnNumber)); |
| break; |
| |
| case Constants::ELEMNAME_NSALIAS: |
| m_stylesheet.processNSAliasElement(name, atts, m_constructionContext); |
| break; |
| |
| case Constants::ELEMNAME_WITHPARAM: |
| case Constants::ELEMNAME_ATTRIBUTE: |
| case Constants::ELEMNAME_APPLY_TEMPLATES: |
| case Constants::ELEMNAME_USE: |
| case Constants::ELEMNAME_CHILDREN: |
| case Constants::ELEMNAME_CHOOSE: |
| case Constants::ELEMNAME_COMMENT: |
| case Constants::ELEMNAME_CONSTRUCT: |
| case Constants::ELEMNAME_CONTENTS: |
| case Constants::ELEMNAME_COPY: |
| case Constants::ELEMNAME_COPY_OF: |
| case Constants::ELEMNAME_DISPLAYIF: |
| case Constants::ELEMNAME_EVAL: |
| case Constants::ELEMNAME_EXPECTEDCHILDREN: |
| case Constants::ELEMNAME_FOREACH: |
| case Constants::ELEMNAME_IF: |
| case Constants::ELEMNAME_CALLTEMPLATE: |
| case Constants::ELEMNAME_MESSAGE: |
| case Constants::ELEMNAME_NUMBER: |
| case Constants::ELEMNAME_OTHERWISE: |
| case Constants::ELEMNAME_PI: |
| case Constants::ELEMNAME_REMOVEATTRIBUTE: |
| case Constants::ELEMNAME_SORT: |
| case Constants::ELEMNAME_TEXT: |
| case Constants::ELEMNAME_VALUEOF: |
| case Constants::ELEMNAME_WHEN: |
| case Constants::ELEMNAME_ELEMENT: |
| case Constants::ELEMNAME_APPLY_IMPORTS: |
| if (inExtensionElement() == false) |
| { |
| const XalanDOMString msg("(StylesheetHandler) " + XalanDOMString(name) + " not allowed inside a stylesheet."); |
| |
| error(msg, locator); |
| } |
| break; |
| |
| case Constants::ELEMNAME_STYLESHEET: |
| processStylesheet(name, atts, locator, fPreserveSpace, fSpaceAttrProcessed); |
| break; |
| |
| default: |
| if (inExtensionElement() == false) |
| { |
| const XalanDOMString msg("Unknown XSL element: " + localName); |
| |
| error(msg, locator); |
| } |
| break; |
| } |
| } |
| |
| |
| void |
| StylesheetHandler::processStylesheet( |
| const XalanDOMChar* name, |
| const AttributeList& atts, |
| const Locator* locator, |
| bool& fPreserveSpace, |
| bool& fSpaceAttrProcessed) |
| { |
| m_stylesheet.setWrapperless(false); |
| m_foundStylesheet = true; |
| |
| const unsigned int nAttrs = atts.getLength(); |
| |
| bool fVersionFound = false; |
| |
| for(unsigned int i = 0; i < nAttrs; i++) |
| { |
| const XalanDOMChar* const aname = atts.getName(i); |
| |
| if(equals(aname, Constants::ATTRNAME_EXCLUDE_RESULT_PREFIXES)) |
| { |
| m_stylesheet.processExcludeResultPrefixes(atts.getValue(i), m_constructionContext); |
| } |
| else if(equals(aname, Constants::ATTRNAME_EXTENSIONELEMENTPREFIXES)) |
| { |
| StringTokenizer tokenizer(atts.getValue(i), |
| Constants::DEFAULT_WHITESPACE_SEPARATOR_STRING); |
| |
| XalanDOMString prefix; |
| |
| while(tokenizer.hasMoreTokens() == true) |
| { |
| tokenizer.nextToken(prefix); |
| |
| const XalanDOMString& extns = getNamespaceForPrefixFromStack(prefix); |
| |
| ExtensionNSHandler* const nsh = new ExtensionNSHandler(extns); |
| |
| m_stylesheet.addExtensionNamespace(extns, nsh); |
| } |
| } |
| else if(equals(aname, Constants::ATTRNAME_ID)) |
| { |
| // |
| } |
| else if(equals(aname, Constants::ATTRNAME_VERSION)) |
| { |
| const XalanDOMChar* const versionStr = atts.getValue(i); |
| assert(versionStr != 0); |
| |
| m_stylesheet.setXSLTVerDeclared(DoubleSupport::toDouble(versionStr)); |
| |
| fVersionFound = true; |
| } |
| else if(processSpaceAttr(aname, atts, i, locator, fPreserveSpace) == true) |
| { |
| fSpaceAttrProcessed = true; |
| } |
| else if(isAttrOK(aname, atts, i) == false) |
| { |
| if(false == m_stylesheet.isWrapperless()) |
| { |
| const XalanDOMString msg( |
| "(StylesheetHandler) " + |
| XalanDOMString(name) + |
| " has an illegal attribute: " + |
| aname); |
| |
| error(msg, locator); |
| } |
| } |
| |
| if(!m_stylesheet.getNamespaces().empty()) |
| { |
| m_stylesheet.setNamespaceDecls(m_stylesheet.getNamespaces().back()); |
| } |
| } |
| |
| if (fVersionFound == false) |
| { |
| error("The stylesheet element did not specify a version attribute.", locator); |
| } |
| } |
| |
| |
| |
| void |
| StylesheetHandler::processExtensionElement( |
| const XalanDOMChar* name, |
| const XalanDOMString& localName, |
| const AttributeList& atts, |
| const Locator* locator) |
| { |
| if (equals(localName, Constants::ATTRNAME_COMPONENTS)) |
| { |
| XalanDOMString prefix; |
| XalanDOMString elements; |
| XalanDOMString functions; |
| |
| const int nAttrs = atts.getLength(); |
| |
| for (int i = 0; i < nAttrs; i++) |
| { |
| const XalanDOMChar* const aname = atts.getName (i); |
| |
| if (equals(aname, Constants::ATTRNAME_PREFIX)) |
| { |
| prefix = atts.getValue(i); |
| } |
| else if (equals(aname, Constants::ATTRNAME_ELEMENTS)) |
| { |
| elements = atts.getValue(i); |
| } |
| else if (equals(aname, Constants::ATTRNAME_FUNCTIONS)) |
| { |
| functions = atts.getValue(i); |
| } |
| else if(!isAttrOK(aname, atts, i)) |
| { |
| const XalanDOMString msg(XalanDOMString(name) + " has an illegal attribute: " + aname); |
| |
| error(msg, locator); |
| } |
| } |
| |
| if (isEmpty(prefix) == true) |
| { |
| const XalanDOMString msg("StylesheetHandler) " + XalanDOMString(name) + " attribute 'prefix' is missing"); |
| |
| error(msg, locator); |
| } |
| |
| // SCOTT: is the line below correct? |
| const XalanDOMString& extns = getNamespaceForPrefixFromStack(prefix); |
| |
| ExtensionNSHandler* nsh = m_stylesheet.lookupExtensionNSHandler(extns); |
| |
| if (nsh == 0) |
| { |
| // The extension namespace might not yet be known... |
| nsh = new ExtensionNSHandler(extns); |
| |
| m_stylesheet.addExtensionNamespace(extns, nsh); |
| |
| assert(m_inExtensionElementStack.empty() == false); |
| |
| m_inExtensionElementStack.back() = true; |
| } |
| |
| if (!isEmpty(elements)) |
| { |
| nsh->setElements(elements); |
| } |
| |
| if (!isEmpty(functions)) |
| { |
| nsh->setFunctions(functions); |
| } |
| |
| m_pLXSLTExtensionNSH = nsh; // hang on to it for processing |
| // endElement on lxslt:script |
| } |
| else if (equals(localName, Constants::ATTRNAME_SCRIPT)) |
| { |
| // process this in end element so that I can see whether I had |
| // a body as well. The default pushing logic will save the |
| // attributes for me. The body will be accumulated into the |
| // following string buffer |
| m_inLXSLTScript = true; |
| clear(m_LXSLTScriptBody); |
| |
| const int nAttrs = atts.getLength(); |
| |
| for (int i = 0; i < nAttrs; i++) |
| { |
| const XalanDOMChar* const aname = atts.getName(i); |
| |
| if (equals(aname, Constants::ATTRNAME_LANG)) |
| { |
| m_LXSLTScriptLang = atts.getValue (i); |
| } |
| else if (equals(aname, Constants::ATTRNAME_SRC)) |
| { |
| m_LXSLTScriptSrcURL = atts.getValue (i); |
| } |
| else if(!isAttrOK(aname, atts, i)) |
| { |
| const XalanDOMString msg(XalanDOMString(name) + " has an illegal attribute: " + aname); |
| |
| error(msg, locator); |
| } |
| } |
| } |
| else |
| { |
| // other xslt4j: element. Not my business. |
| } |
| } |
| |
| |
| |
| void |
| StylesheetHandler::processPreserveStripSpace( |
| const XalanDOMChar* name, |
| const AttributeList& atts, |
| const Locator* locator, |
| int xslToken) |
| { |
| ElemEmpty nsNode(m_constructionContext, m_stylesheet, getLineNumber(locator), getColumnNumber(locator)); |
| |
| const unsigned int nAttrs = atts.getLength(); |
| |
| bool foundIt = false; |
| |
| const bool isPreserveSpace = Constants::ELEMNAME_PRESERVESPACE == xslToken? true : false; |
| |
| for(unsigned int i = 0; i < nAttrs; i++) |
| { |
| const XalanDOMChar* const aname = atts.getName(i); |
| |
| if(equals(aname, Constants::ATTRNAME_ELEMENTS)) |
| { |
| foundIt = true; |
| |
| StringTokenizer tokenizer(atts.getValue(i), |
| Constants::DEFAULT_WHITESPACE_SEPARATOR_STRING); |
| |
| while(tokenizer.hasMoreTokens()) |
| { |
| // Use only the root, at least for right now. |
| const XalanDOMString wildcardName = tokenizer.nextToken(); |
| |
| /** |
| * Creating a match pattern is too much overhead, but it's a reasonably |
| * easy and safe way to do this right now. |
| */ |
| const XPath* const matchPat = |
| m_constructionContext.createMatchPattern(0, wildcardName, nsNode); |
| |
| if(isPreserveSpace == true) |
| { |
| m_stylesheet.getStylesheetRoot().pushWhitespacePreservingElement(matchPat); |
| } |
| else |
| { |
| m_stylesheet.getStylesheetRoot().pushWhitespaceStrippingElement(matchPat); |
| } |
| } |
| } |
| else if(!isAttrOK(aname, atts, i)) |
| { |
| const XalanDOMString msg(XalanDOMString(name) + " has an illegal attribute: " + aname); |
| |
| error(msg, locator); |
| } |
| } |
| |
| if(!foundIt && inExtensionElement() == false) |
| { |
| const XalanDOMString msg("(StylesheetHandler) " + XalanDOMString(name) + |
| " requires a " + Constants::ATTRNAME_ELEMENTS + " attribute."); |
| |
| error(msg, locator); |
| } |
| } |
| |
| |
| |
| void |
| StylesheetHandler::appendChildElementToParent( |
| ElemTemplateElement* elem, |
| const Locator* locator) |
| { |
| ElemTemplateElement* const parent = m_elemStack.back(); |
| |
| try |
| { |
| parent->appendChildElem(elem); |
| } |
| catch(const XalanDOMException& e) |
| { |
| if (e.getExceptionCode() == XalanDOMException::HIERARCHY_REQUEST_ERR) |
| { |
| // $$$ ToDo: There is a bug in the version of gcc that |
| // we're using when the optimizer is enabled. Constructing |
| // this error message from the parameter results in an internal |
| // compiler error, so I'm using a local variable instead. |
| #if defined(__GNUC__) |
| const ElemTemplateElement* const localElem = elem; |
| |
| XalanDOMString theMessage(localElem->getElementName()); |
| |
| #else |
| XalanDOMString theMessage(elem->getElementName()); |
| #endif |
| |
| append(theMessage, " is not a valid child of "); |
| append(theMessage, parent->getElementName()); |
| |
| error(theMessage, locator); |
| } |
| |
| throw; |
| } |
| |
| m_elemStackParentedElements.insert(elem); |
| } |
| |
| |
| |
| void |
| StylesheetHandler::doCleanup() |
| { |
| if (m_locatorsPushed > 0) |
| { |
| m_constructionContext.popLocatorStack(); |
| |
| --m_locatorsPushed; |
| } |
| |
| // Pop anything that's not an empty element... |
| while(m_elemStack.empty() == false && |
| m_elemStack.back()->getXSLToken() != Constants::ELEMNAME_UNDEFINED) |
| { |
| m_elemStackParentedElements.erase(m_elemStack.back()); |
| m_elemStack.pop_back(); |
| } |
| } |
| |
| |
| |
| static bool |
| stackContains( |
| const Stylesheet::URLStackType& stack, |
| const XalanDOMString& urlString) |
| { |
| const Stylesheet::URLStackType::size_type n = stack.size(); |
| |
| bool contains = false; |
| |
| for(Stylesheet::URLStackType::size_type i = 0; i < n && contains == false; ++i) |
| { |
| if(equals(stack[i], urlString)) |
| { |
| contains = true; |
| } |
| } |
| |
| return contains; |
| } |
| |
| |
| |
| void |
| StylesheetHandler::processImport( |
| const XalanDOMChar* name, |
| const AttributeList& atts, |
| const Locator* locator) |
| { |
| const unsigned int nAttrs = atts.getLength(); |
| |
| bool foundIt = false; |
| |
| for(unsigned int i = 0; i < nAttrs; i++) |
| { |
| const XalanDOMChar* const aname = atts.getName(i); |
| |
| if(equals(aname, Constants::ATTRNAME_HREF)) |
| { |
| foundIt = true; |
| |
| if(m_foundNotImport) |
| { |
| error("Imports can only occur as the first elements in the stylesheet.", locator); |
| } |
| |
| const XalanDOMString saved_XSLNameSpaceURL = m_stylesheet.getXSLTNamespaceURI(); |
| |
| const XalanDOMString href(atts.getValue(i)); |
| |
| Stylesheet::URLStackType& includeStack = m_stylesheet.getIncludeStack(); |
| assert(includeStack.size() > 0); |
| |
| const XalanDOMString hrefUrl = m_constructionContext.getURLStringFromString(href, includeStack.back()); |
| assert(length(hrefUrl) != 0); |
| |
| Stylesheet::URLStackType& importStack = m_stylesheet.getStylesheetRoot().getImportStack(); |
| |
| if(stackContains(importStack, hrefUrl)) |
| { |
| const XalanDOMString msg(hrefUrl + " is directly or indirectly importing itself."); |
| |
| error(msg, locator); |
| } |
| |
| importStack.push_back(hrefUrl); |
| |
| // This will take care of cleaning up the stylesheet if an exception |
| // is thrown. |
| XalanAutoPtr<Stylesheet> importedStylesheet( |
| m_constructionContext.create( |
| m_stylesheet.getStylesheetRoot(), |
| hrefUrl)); |
| |
| StylesheetHandler tp(*importedStylesheet.get(), m_constructionContext); |
| |
| m_constructionContext.parseXML(hrefUrl, &tp, 0); |
| |
| // Add it to the front of the imports, releasing the XalanAutoPtr... |
| m_stylesheet.addImport(importedStylesheet.release(), true); |
| |
| assert(equals(importStack.back(), hrefUrl)); |
| importStack.pop_back(); |
| |
| m_stylesheet.setXSLTNamespaceURI(saved_XSLNameSpaceURL); |
| } |
| else if(!isAttrOK(aname, atts, i)) |
| { |
| const XalanDOMString msg(XalanDOMString(name) + " has an illegal attribute: " + aname); |
| |
| error(msg, locator); |
| } |
| } |
| |
| if(!foundIt) |
| { |
| const XalanDOMString msg("Could not find href attribute for " + XalanDOMString(name)); |
| |
| error(msg, locator); |
| } |
| } |
| |
| |
| void |
| StylesheetHandler::processInclude( |
| const XalanDOMChar* name, |
| const AttributeList& atts, |
| const Locator* locator) |
| { |
| const unsigned int nAttrs = atts.getLength(); |
| |
| bool foundIt = false; |
| |
| for(unsigned int i = 0; i < nAttrs; i++) |
| { |
| const XalanDOMChar* const aname = atts.getName(i); |
| |
| if(equals(aname, Constants::ATTRNAME_HREF)) |
| { |
| foundIt = true; |
| |
| PushPopIncludeState theStateHandler(*this); |
| |
| const XalanDOMString href(atts.getValue(i)); |
| |
| assert(c_wstr(m_stylesheet.getIncludeStack().back()) != 0); |
| const XalanDOMString hrefUrl = m_constructionContext.getURLStringFromString(href, m_stylesheet.getIncludeStack().back()); |
| |
| if(stackContains(m_stylesheet.getIncludeStack(), hrefUrl)) |
| { |
| XalanDOMString msg(hrefUrl + " is directly or indirectly including itself."); |
| |
| error(msg, locator); |
| } |
| |
| m_stylesheet.getIncludeStack().push_back(hrefUrl); |
| |
| m_constructionContext.parseXML(hrefUrl, this, 0); |
| |
| assert(equals(m_stylesheet.getIncludeStack().back(), hrefUrl)); |
| m_stylesheet.getIncludeStack().pop_back(); |
| } |
| else if(!isAttrOK(aname, atts, i)) |
| { |
| const XalanDOMString msg(XalanDOMString(name) + " has an illegal attribute: " + aname); |
| |
| error(msg, locator); |
| } |
| } |
| |
| if(!foundIt) |
| { |
| const XalanDOMString msg("Could not find href attribute for " + XalanDOMString(name)); |
| |
| error(msg, locator); |
| } |
| } |
| |
| |
| |
| void |
| StylesheetHandler::endElement(const XMLCh* const name) |
| { |
| const Locator* const locator = m_constructionContext.getLocatorFromStack(); |
| |
| #if !defined(XALAN_NO_NAMESPACES) |
| using std::for_each; |
| #endif |
| |
| processAccumulatedText(); |
| |
| // Clean up the whitespace elements. |
| for_each(m_whiteSpaceElems.begin(), |
| m_whiteSpaceElems.end(), |
| DeleteFunctor<ElemTextLiteral>()); |
| |
| m_whiteSpaceElems.clear(); |
| |
| m_stylesheet.popNamespaces(); |
| |
| assert(m_elemStack.empty() == false); |
| |
| m_lastPopped = m_elemStack.back(); |
| m_elemStack.pop_back(); |
| m_elemStackParentedElements.erase(m_lastPopped); |
| m_lastPopped->finishedConstruction(); |
| |
| const int tok = m_lastPopped->getXSLToken(); |
| |
| if(Constants::ELEMNAME_TEMPLATE == tok) |
| { |
| m_inTemplate = false; |
| } |
| else if((Constants::ELEMNAME_PARAMVARIABLE == tok) || |
| Constants::ELEMNAME_VARIABLE == tok) |
| { |
| #if defined(XALAN_OLD_STYLE_CASTS) |
| const ElemVariable* const var = (const ElemVariable*)m_lastPopped; |
| #else |
| const ElemVariable* const var = static_cast<const ElemVariable*>(m_lastPopped); |
| #endif |
| |
| if(var->isTopLevel() == true) |
| { |
| // Top-level param or variable |
| m_inTemplate = false; |
| } |
| } |
| else if(Constants::ELEMNAME_DEFINEATTRIBUTESET == tok) |
| { |
| m_inTemplate = false; |
| } |
| else if (tok == Constants::ELEMNAME_UNDEFINED || |
| tok == Constants::ELEMNAME_TEXT) |
| { |
| // These are stray elements, so stuff them away |
| // to be deleted when we're finished... |
| m_strayElements.push_back(m_lastPopped); |
| } |
| |
| // BEGIN SANJIVA CODE |
| if (m_inLXSLTScript) |
| { |
| if (isEmpty(m_LXSLTScriptLang)) |
| { |
| const XalanDOMString msg(XalanDOMString(name) + " attribute \'lang\' is missing"); |
| |
| error(msg, locator); |
| } |
| if (m_pLXSLTExtensionNSH == 0) |
| { |
| const XalanDOMString msg("(StylesheetHandler) misplaced " + XalanDOMString(name) + " element?? Missing container element " + "'component'"); |
| |
| error(msg, locator); |
| } |
| |
| m_pLXSLTExtensionNSH->setScript(m_LXSLTScriptLang, m_LXSLTScriptSrcURL, m_LXSLTScriptBody); |
| |
| // reset state |
| m_inLXSLTScript = false; |
| clear(m_LXSLTScriptLang); |
| clear(m_LXSLTScriptSrcURL); |
| clear(m_LXSLTScriptBody); |
| m_pLXSLTExtensionNSH = 0; |
| } |
| // END SANJIVA CODE |
| |
| assert(m_inExtensionElementStack.empty() == false); |
| |
| m_inExtensionElementStack.pop_back(); |
| |
| assert(m_preserveSpaceStack.empty() == false); |
| |
| m_preserveSpaceStack.pop_back(); |
| } |
| |
| |
| |
| void |
| StylesheetHandler::characters( |
| const XMLCh* const chars, |
| const unsigned int length) |
| { |
| accumulateText(chars, length); |
| } |
| |
| |
| |
| void |
| StylesheetHandler::cdata( |
| const XMLCh* const chars, |
| const unsigned int length) |
| { |
| accumulateText(chars, length); |
| |
| processText(chars, length); |
| |
| m_lastPopped = 0; |
| } |
| |
| |
| |
| void |
| StylesheetHandler::ignorableWhitespace( |
| const XMLCh* const /*chars*/, |
| const unsigned int /*length*/) |
| { |
| // Ignore! |
| m_lastPopped = 0; |
| } |
| |
| |
| |
| void |
| StylesheetHandler::processingInstruction( |
| const XMLCh* const /*target*/, |
| const XMLCh* const /*data*/) |
| { |
| if (isXMLWhitespace(m_accumulateText) == false) |
| { |
| processAccumulatedText(); |
| } |
| else |
| { |
| clear(m_accumulateText); |
| } |
| } |
| |
| |
| |
| void |
| StylesheetHandler::comment(const XMLCh* const /*data*/) |
| { |
| processAccumulatedText(); |
| } |
| |
| |
| |
| void |
| StylesheetHandler::entityReference(const XMLCh* const /*name*/) |
| { |
| processAccumulatedText(); |
| } |
| |
| |
| |
| void |
| StylesheetHandler::resetDocument() |
| { |
| clear(m_accumulateText); |
| } |
| |
| |
| |
| void |
| StylesheetHandler::charactersRaw( |
| const XMLCh* const /* chars */, |
| const unsigned int /* length */) |
| { |
| // No action for the moment. |
| } |
| |
| |
| |
| void |
| StylesheetHandler::processText( |
| const XMLCh* chars, |
| XalanDOMString::size_type length) |
| { |
| if(m_inTemplate) |
| { |
| ElemTemplateElement* parent = m_elemStack.back(); |
| assert(parent != 0); |
| |
| assert(m_preserveSpaceStack.empty() == false); |
| |
| bool preserveSpace = m_preserveSpaceStack.back(); |
| bool disableOutputEscaping = false; |
| |
| if (preserveSpace == false && parent->getXSLToken() == Constants::ELEMNAME_TEXT) |
| { |
| #if defined(XALAN_OLD_STYLE_CASTS) |
| disableOutputEscaping = ((ElemText*)parent)->getDisableOutputEscaping(); |
| #else |
| disableOutputEscaping = static_cast<ElemText*>(parent)->getDisableOutputEscaping(); |
| #endif |
| preserveSpace = true; |
| |
| parent = m_elemStack[m_elemStack.size() - 2]; |
| } |
| |
| const Locator* const locator = m_constructionContext.getLocatorFromStack(); |
| |
| const int lineNumber = (0 != locator) ? locator->getLineNumber() : 0; |
| const int columnNumber = (0 != locator) ? locator->getColumnNumber() : 0; |
| |
| XalanAutoPtr<ElemTextLiteral> elem(new ElemTextLiteral(m_constructionContext, |
| m_stylesheet, |
| lineNumber, |
| columnNumber, |
| chars, |
| 0, |
| length, |
| true, |
| preserveSpace, |
| disableOutputEscaping)); |
| |
| const bool isWhite = elem->isWhitespace(); |
| |
| if(preserveSpace || (!preserveSpace && !isWhite)) |
| { |
| while(!m_whiteSpaceElems.empty()) |
| { |
| parent->appendChildElem(m_whiteSpaceElems.back()); |
| |
| m_whiteSpaceElems.pop_back(); |
| } |
| |
| parent->appendChildElem(elem.get()); |
| |
| elem.release(); |
| } |
| else if(isWhite) |
| { |
| bool shouldPush = true; |
| |
| ElemTemplateElement* const last = parent->getLastChildElem(); |
| |
| if(0 != last) |
| { |
| // If it was surrounded by xsl:text, it will count as an element. |
| const bool isPrevCharData = |
| Constants::ELEMNAME_TEXTLITERALRESULT == last->getXSLToken(); |
| |
| const bool isLastPoppedXSLText = (m_lastPopped != 0) && |
| (Constants::ELEMNAME_TEXT == m_lastPopped->getXSLToken()); |
| |
| if(isPrevCharData && ! isLastPoppedXSLText) |
| { |
| parent->appendChildElem(elem.get()); |
| |
| elem.release(); |
| |
| shouldPush = false; |
| } |
| } |
| |
| if(shouldPush) |
| { |
| m_whiteSpaceElems.push_back(elem.get()); |
| |
| elem.release(); |
| } |
| } |
| } |
| else if (m_inLXSLTScript) |
| { |
| append(m_LXSLTScriptBody, chars); |
| } |
| |
| // TODO: Flag error if text inside of stylesheet |
| } |
| |
| |
| |
| void |
| StylesheetHandler::accumulateText( |
| const XMLCh* chars, |
| XalanDOMString::size_type length) |
| { |
| if(m_inTemplate) |
| { |
| append(m_accumulateText, chars, length); |
| } |
| } |
| |
| |
| |
| void |
| StylesheetHandler::processAccumulatedText() |
| { |
| if (isEmpty(m_accumulateText) == false) |
| { |
| processText(m_accumulateText.c_str(), length(m_accumulateText)); |
| |
| clear(m_accumulateText); |
| } |
| } |
| |
| |
| |
| bool |
| StylesheetHandler::inExtensionElement() const |
| { |
| #if !defined(XALAN_NO_NAMESPACES) |
| using std::find; |
| #endif |
| |
| if (find( |
| m_inExtensionElementStack.rbegin(), |
| m_inExtensionElementStack.rend(), |
| true) != m_inExtensionElementStack.rend()) |
| { |
| return true; |
| } |
| else |
| { |
| return false; |
| } |
| } |
| |
| |
| |
| void |
| StylesheetHandler::error( |
| const char* theMessage, |
| const Locator* theLocator) const |
| { |
| m_constructionContext.error(theMessage, 0, theLocator); |
| } |
| |
| |
| |
| void |
| StylesheetHandler::error( |
| const XalanDOMString& theMessage, |
| const Locator* theLocator) const |
| { |
| m_constructionContext.error(theMessage, 0, theLocator); |
| } |
| |
| |
| |
| StylesheetHandler::PushPopIncludeState::PushPopIncludeState(StylesheetHandler& theHandler) : |
| m_handler(theHandler), |
| m_elemStack(theHandler.m_elemStack), |
| m_elemStackParentedElements(theHandler.m_elemStackParentedElements), |
| m_pTemplate(theHandler.m_pTemplate), |
| m_lastPopped(theHandler.m_lastPopped), |
| m_inTemplate(theHandler.m_inTemplate), |
| m_foundStylesheet(theHandler.m_foundStylesheet), |
| m_XSLNameSpaceURL(theHandler.m_stylesheet.getXSLTNamespaceURI()), |
| m_foundNotImport(theHandler.m_foundNotImport), |
| m_namespaceDecls(), |
| m_namespaces(), |
| m_namespacesHandler(), |
| m_inExtensionElementStack() |
| { |
| clear(m_handler.m_accumulateText); |
| m_handler.m_elemStack.clear(); |
| m_handler.m_pTemplate = 0; |
| m_handler.m_lastPopped = 0; |
| m_handler.m_inTemplate = false; |
| m_handler.m_foundStylesheet = false; |
| m_handler.m_foundNotImport = false; |
| |
| // This is much more efficient, since we're just swapping |
| // underlying data. This clears out the stack as well... |
| m_namespaceDecls.swap(theHandler.m_stylesheet.getNamespaceDecls()); |
| m_namespaces.swap(theHandler.m_stylesheet.getNamespaces()); |
| m_namespacesHandler.swap(theHandler.m_stylesheet.getNamespacesHandler()); |
| m_inExtensionElementStack.swap(theHandler.m_inExtensionElementStack); |
| m_preserveSpaceStack.swap(theHandler.m_preserveSpaceStack); |
| } |
| |
| |
| |
| StylesheetHandler::PushPopIncludeState::~PushPopIncludeState() |
| { |
| // Clean up the element stack vector |
| #if !defined(XALAN_NO_NAMESPACES) |
| using std::for_each; |
| #endif |
| |
| // Clean up the element stack vector |
| for_each(m_handler.m_elemStack.begin(), |
| m_handler.m_elemStack.end(), |
| DeleteFunctor<ElemTemplateElement>()); |
| |
| clear(m_handler.m_accumulateText); |
| m_handler.m_elemStack = m_elemStack; |
| m_handler.m_elemStackParentedElements = m_elemStackParentedElements; |
| m_handler.m_pTemplate = m_pTemplate; |
| m_handler.m_lastPopped = m_lastPopped; |
| m_handler.m_inTemplate = m_inTemplate; |
| m_handler.m_foundStylesheet = m_foundStylesheet; |
| m_handler.m_stylesheet.setXSLTNamespaceURI(m_XSLNameSpaceURL); |
| m_handler.m_foundNotImport = m_foundNotImport; |
| |
| // This is much more efficient, since we're just swapping |
| // underlying data. |
| m_handler.m_stylesheet.getNamespaceDecls().swap(m_namespaceDecls); |
| m_handler.m_stylesheet.getNamespaces().swap(m_namespaces); |
| m_handler.m_stylesheet.getNamespacesHandler().swap(m_namespacesHandler); |
| m_handler.m_inExtensionElementStack.swap(m_inExtensionElementStack); |
| m_handler.m_preserveSpaceStack.swap(m_preserveSpaceStack); |
| } |
| |
| |
| |
| const XalanDOMString StylesheetHandler::s_emptyString; |
| |
| XalanDOMString s_localPart; |
| |
| XalanQNameByReference s_spaceAttrQName; |
| |
| const XalanQName& StylesheetHandler::s_spaceAttrQName = ::s_spaceAttrQName; |
| |
| |
| |
| void |
| StylesheetHandler::initialize() |
| { |
| ::s_localPart = XALAN_STATIC_UCODE_STRING("space"); |
| |
| ::s_spaceAttrQName.setLocalPart(::s_localPart); |
| |
| ::s_spaceAttrQName.setNamespace(DOMServices::s_XMLNamespaceURI); |
| } |
| |
| |
| |
| void |
| StylesheetHandler::terminate() |
| { |
| releaseMemory(::s_localPart); |
| |
| ::s_spaceAttrQName.clear(); |
| } |