src/xalanc/XSLT/Stylesheet.hpp (373 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #if !defined(XALAN_STYLESHEET_HEADER_GUARD) #define XALAN_STYLESHEET_HEADER_GUARD // Base include file. Must be first. #include "XSLTDefinitions.hpp" #include <xalanc/XalanDOM/XalanNode.hpp> #include <xalanc/XalanDOM/XalanDOMString.hpp> #include <xalanc/Include/XalanVector.hpp> #include <xalanc/Include/XalanMap.hpp> #include <xalanc/PlatformSupport/PrefixResolver.hpp> #include <xalanc/XPath/NameSpace.hpp> #include <xalanc/XPath/XalanQNameByReference.hpp> #include <xalanc/XPath/XPath.hpp> #include <xalanc/XSLT/NamespacesHandler.hpp> #include <xalanc/XSLT/KeyDeclaration.hpp> #include <xalanc/XSLT/StylesheetConstructionContext.hpp> #include <xalanc/XSLT/StylesheetExecutionContext.hpp> #include <xalanc/XSLT/XalanSpaceNodeTester.hpp> namespace XALAN_CPP_NAMESPACE { class ExtensionNSHandler; class XalanDecimalFormatSymbols; class ElemDecimalFormat; class ElemTemplate; class ElemTemplateElement; class ElemVariable; class KeyTable; class NodeRefListBase; class PrefixResolver; class StylesheetConstructionContext; class StylesheetRoot; class XalanMatchPatternData; class XalanQName; class XObject; class StylesheetExecutionContext; typedef XalanVector<const XalanMatchPatternData*> PatternTableVectorTypeDecl; XALAN_USES_MEMORY_MANAGER(PatternTableVectorTypeDecl) /** * This class represents the base stylesheet or an "import" stylesheet. * "include" stylesheets are combined with the including stylesheet. */ class XALAN_XSLT_EXPORT Stylesheet : public PrefixResolver { public: typedef StylesheetExecutionContext::ParamVectorType ParamVectorType; typedef XalanQName::NamespaceVectorType NamespaceVectorType; typedef XalanQName::NamespacesStackType NamespacesStackType; typedef XalanVector<ElemVariable*> ElemVariableVectorType; typedef XalanVector<KeyDeclaration> KeyDeclarationVectorType; typedef XalanVector<Stylesheet*> StylesheetVectorType; typedef XalanVector<XalanDOMString> URLStackType; typedef XalanVector<ElemDecimalFormat*> ElemDecimalFormatVectorType; typedef XalanVector<XalanSpaceNodeTester> WhitespaceElementsVectorType; typedef PatternTableVectorTypeDecl PatternTableVectorType; typedef XalanMap<XalanDOMString, ExtensionNSHandler*> ExtensionNamespacesMapType; typedef XalanMap<XalanQNameByReference, const ElemTemplate* > ElemTemplateMapType; typedef XalanMap<const XalanNode*, KeyTable* > KeyTablesTableType; typedef XalanMap<XalanDOMString, PatternTableVectorType> PatternTableMapType; typedef StylesheetConstructionContext::GetCachedString GetCachedString; /** * Constructor for a Stylesheet needs a Document. * @exception XSLProcessorException thrown if the active ProblemListener and XMLParserLiaison decide * the error condition is severe enough to halt processing. */ Stylesheet( StylesheetRoot& root, const XalanDOMString& baseIdentifier, StylesheetConstructionContext& constructionContext); virtual ~Stylesheet(); static Stylesheet* create(MemoryManager& theManager, StylesheetRoot& root, const XalanDOMString& baseIdentifier, StylesheetConstructionContext& constructionContext); MemoryManager& getMemoryManager() { return m_elementPatternTable.getMemoryManager(); } /** * Retrieve XSLT version number * * @return number representing XSLT version */ double getXSLTVerDeclared() const { return m_XSLTVerDeclared; } /** * Set XSLT version number * * @param ver number representing XSLT version */ void setXSLTVerDeclared(double ver) { m_XSLTVerDeclared = ver; } /** * Retrieve the root stylesheet object * * @return const reference to the stylesheet object */ const StylesheetRoot& getStylesheetRoot() const { return m_stylesheetRoot; } /** * Retrieve the root stylesheet object * * @return reference to the stylesheet object */ StylesheetRoot& getStylesheetRoot() { return m_stylesheetRoot; } /** * Retrieve the stack of namespace lists * * @return vector of namespace vectors */ const NamespacesStackType& getNamespaces() const { return m_namespaces; } /** * Retrieve the stack of namespace lists * * @return vector of namespace vectors */ NamespacesStackType& getNamespaces() { return m_namespaces; } const NamespacesHandler& getNamespacesHandler() const { return m_namespacesHandler; } NamespacesHandler& getNamespacesHandler() { return m_namespacesHandler; } /** * Retrieve the list of namespace declarations currently in effect * * @return vector of namespace vectors */ const NamespaceVectorType& getNamespaceDecls() const { return m_namespaceDecls; } /** * Retrieve the list of namespace declarations currently in effect * * @return vector of namespace vectors */ NamespaceVectorType& getNamespaceDecls() { return m_namespaceDecls; } /** * Set the list of namespace declarations currently in effect * * @param ns vector of namespace vectors */ void setNamespaceDecls(const NamespaceVectorType& ns) { m_namespaceDecls = ns; } /** * Push the namespace declarations from the current attribute * list onto the namespace stack. * * @param atts attribute list constaining namespaces */ void pushNamespaces(const AttributeListType& atts); /** * Pop a namespace declaration from the namespace stack. */ void popNamespaces() { assert(m_namespaces.empty() == false); m_namespaces.pop_back(); } void addWhitespaceElement(const XalanSpaceNodeTester& theTester); /** * Called after construction is completed. */ virtual void postConstruction(StylesheetConstructionContext& constructionContext); /** * See if this is a xmlns attribute, and, if so, process it. * * @param attrName qualified name of attribute * @param atts attribute list where the element comes from (not used at * this time) * @param which index into the attribute list (not used at this time) * @return true if this is a namespace name */ bool isAttrOK( const XalanDOMChar* attrName, const AttributeListType& atts, XalanSize_t which, StylesheetConstructionContext& constructionContext) const; /** * Get the namespace from a qualified name. * * @param nodeName name of node * @return namespace string for node, or null if not found. */ const XalanDOMString* getNamespaceFromStack( const XalanDOMString& nodeName, XalanDOMString& theBuffer) const { return getNamespaceFromStack(nodeName.c_str(), theBuffer); } /** * Get the namespace from a qualified name. * * @param nodeName name of node * @return namespace string for node, or null if not found. */ const XalanDOMString* getNamespaceFromStack( const XalanDOMChar* nodeName, XalanDOMString& theBuffer) const; /** * Get the namespace from a prefix by searching the stack of namespace * lists. * * @param prefix prefix to search * @return namespace corresponding to prefix, or null if not found. */ const XalanDOMString* getNamespaceForPrefixFromStack(const XalanDOMString& prefix) const { return XalanQName::getNamespaceForPrefix(m_namespaces, prefix); } /** * Get the namespace from a prefix by searching the stack of namespace * lists. * * @param prefix prefix to search * @return namespace corresponding to prefix, or null if not found. */ const XalanDOMString* getNamespaceForPrefixFromStack(const XalanDOMChar* prefix) const { assert(prefix != 0); return XalanQName::getNamespaceForPrefix(m_namespaces, (const XalanDOMChar*)prefix); } /** * Get the namespace for a prefix, and report an error if it wasn't found. * * @param prefix prefix to search * @param constructionContext The current construction context * @return namespace corresponding to prefix, or null if not found. */ const XalanDOMString* getNamespaceForPrefix( const XalanDOMString& prefix, StylesheetConstructionContext& constructionContext) const; /** * Get the namespace for a prefix, and report an error if it wasn't found. * * @param prefix prefix to search * @param constructionContext The current construction context * @return namespace corresponding to prefix, or null if not found. */ const XalanDOMString* getNamespaceForPrefix( const XalanDOMChar* prefix, StylesheetConstructionContext& constructionContext) const; /** * See if a namespace should be excluded. * * @param theConstructionContext the current construction context. * @param theValue the prefix of the namespace. * @return */ void processExcludeResultPrefixes( StylesheetConstructionContext& theConstructionContext, const XalanDOMChar* theValue) { m_namespacesHandler.processExcludeResultPrefixes( theConstructionContext, theValue, m_namespaces); } /** * Add a template to the list of names templates * * @param theTemplate template to add * @param constructionContext context for construction */ void addTemplate( ElemTemplate* theTemplate, StylesheetConstructionContext& constructionContext); /** * Process an attribute that has the value of 'yes' or 'no'. * * @param aname name of attribute * @param val value * @param constructionContext context for construction * @return true if value equals string constant for "yes," false otherwise */ bool getYesOrNo( const XalanDOMChar* aname, const XalanDOMChar* val, StylesheetConstructionContext& constructionContext) const; /** * Retrieve the base identifier with which this stylesheet is associated. * * @return string for base identifier */ const XalanDOMString& getBaseIdentifier() const { return m_baseIdent; } /** * Retrieve the base identifier for the most recently * included stylesheet. This will return the same value * as getBaseIdentifier(), if no include is being * processed. * * @return string for base identifier */ const XalanDOMString& getCurrentIncludeBaseIdentifier() const { return m_includeStack.empty() == true ? getBaseIdentifier() : m_includeStack.back(); } /** * Process an xsl:namespace-alias element. * * @param name the element name. * @param attrs the current attribute list * @param constructionContext the active construction context */ void processNSAliasElement( const XalanDOMChar* name, const AttributeListType& atts, StylesheetConstructionContext& constructionContext); /** * Process an xsl:decimal-format element. * * @param elemDecimalFormat the element */ void processDecimalFormatElement( StylesheetConstructionContext& constructionContext, const AttributeListType& atts, const Locator* locator = 0); /** * Retrieve the XalanDecimalFormatSymbols instance associated with * the QName. * * @param theQName the QName for the lookup * @return a pointer to the matching instance, or 0 if none was found */ const XalanDecimalFormatSymbols* getDecimalFormatSymbols(const XalanQName& theQName) const; /** * Add an imported stylesheet. * * @param theStylesheet The stylesheet to add. */ void addImport(Stylesheet* theStylesheet) { m_imports.insert(m_imports.begin(), theStylesheet); } /** * whether there is a wrapper template * * @return true is there is a wrapper */ bool isWrapperless() const { return m_isWrapperless; } ElemTemplateElement* initWrapperless( StylesheetConstructionContext& constructionContext, const Locator* locator); /** * Retrieve the stack of who's including who * * @return stack of includes */ URLStackType& getIncludeStack() { return m_includeStack; } /** * Process the xsl:key element. * * @param nsContext The PrefixResolver instance for namespace prefixes. * @param atts The attribute list for element. * #param locator The Locator instance for error reporting, if any. May be 0. * @param constructionContext The current construction context. */ void processKeyElement( const PrefixResolver& nsContext, const AttributeListType& atts, const Locator* locator, StylesheetConstructionContext& constructionContext); /** * Locate a template via the "name" attribute. * * @param name qualified name of template * @return pointer to template found or 0 if none found */ const ElemTemplate* findNamedTemplate(const XalanQName& qname) const; /** * Given a target element, find the template that best matches in the given * XSL document, according to the rules specified in the xsl draft. * * @param executionContext current execution context * @param targetNode element that needs a rule * @return pointer to rule that best matches targetNode */ const ElemTemplate* findTemplate( StylesheetExecutionContext& executionContext, XalanNode* targetNode) const { assert(targetNode != 0); return findTemplate( executionContext, targetNode, targetNode->getNodeType(), s_emptyQName, false); } /** * Given a target element, find the template that best matches in the given * XSL document, according to the rules specified in the xsl draft. * * @param executionContext current execution context * @param targetNode node that needs a rule * @param targetNodeType the type of targetNode * @param mode string indicating the mode * @param onlyUseImports only use imports, do not use any templates from the stylesheet itself * @return pointer to rule that best matches targetElem */ const ElemTemplate* findTemplate( StylesheetExecutionContext& executionContext, XalanNode* targetNode, XalanNode::NodeType targetNodeType, const XalanQName& mode, bool onlyUseImports) const; /** * Add object to vector of match patterns if not already there. * * @param thePattern pattern to add * @param theVector vector of patterns to add to */ static void addObjectIfNotFound( const XalanMatchPatternData* thePattern, PatternTableVectorType& theVector); /** * Add object to array of match patterns if not already there. * theArraySize size will be incremented if the pattern was * added. * * @param thePattern pattern to add * @param theArray vector of patterns to add to * @param theArraySize The size of the array */ static void addObjectIfNotFound( const XalanMatchPatternData* thePattern, const XalanMatchPatternData* theArray[], XalanSize_t& theArraySize); /** * Given a name, locate the start of a list of * possible templates that match that name. If * none match, then use the default list. * * @param theName The name to match */ const PatternTableVectorType* locateElementMatchPatternDataList(const XalanDOMString& theName) const; /** * Given a name, locate the start of a list of * possible templates that match that name. If * none match, then use the default list. * * @param theName The name to match */ const PatternTableVectorType* locateAttributeMatchPatternDataList(const XalanDOMString& theName) const; /** * Given a XalanNode, locate the start of a list of * possible templates that match it. * * @param XalanNode The node to match */ const PatternTableVectorType* locateMatchPatternDataList( const XalanNode& theNode, XalanNode::NodeType targetNodeType) const; /** * Add an extension namespace handler. This provides methods for calling * an element extension as well as for function calls (which is passed * on to XPath). * * @param constructionContext The current construction context. * @param uri The namespace URI of the extension. */ void processExtensionNamespace( StylesheetConstructionContext& theConstructionContext, const XalanDOMString& uri); /** * Return the handler for a given extension namespace. * * @param uri the URI of the extension namespace. * @return pointer to extension handler */ ExtensionNSHandler* lookupExtensionNSHandler(const XalanDOMString& uri) const { const ExtensionNamespacesMapType::const_iterator it = m_extensionNamespaces.find(uri); return it == m_extensionNamespaces.end() ? 0 : (*it).second; } /** * Set a top level variable. * * @param var top-level variable declared with "xsl:variable" or * xsl:param-variable. */ void setTopLevelVariable(ElemVariable* var) { m_topLevelVariables.push_back(var); } /** * Set a list of top level variables in the specified execution context * stylesheet. * * @param executionContext current execution context * @param topLevelParams list of top level parameters */ void pushTopLevelVariables( StylesheetExecutionContext& executionContext, const ParamVectorType& topLevelParams) const; // These interfaces are inherited from PrefixResolver... virtual const XalanDOMString* getNamespaceForPrefix(const XalanDOMString& prefix) const; virtual const XalanDOMString& getURI() const; const XalanDOMString& getXSLTNamespaceURI() const { return m_XSLTNamespaceURI; } void setXSLTNamespaceURI(const XalanDOMString& theURI) { m_XSLTNamespaceURI = theURI; } const ElemTemplate* getFirstTemplate() const { return m_firstTemplate; } protected: /** * The root of the stylesheet tree. */ StylesheetRoot& m_stylesheetRoot; /** * The base URL of the XSL document. */ XalanDOMString m_baseIdent; /** * Table of KeyDeclaration objects, which are set by the * xsl:key element. */ KeyDeclarationVectorType m_keyDeclarations; WhitespaceElementsVectorType m_whitespaceElements; static const XalanQNameByReference s_emptyQName; private: // Not defined... Stylesheet(const Stylesheet&); Stylesheet& operator=(const Stylesheet&); bool operator==(const Stylesheet&) const; void error( StylesheetConstructionContext& theContext, XalanMessages::Codes theErrorCode, const Locator* theLocator, const XalanDOMChar* theParam1 = 0, const XalanDOMChar* theParam2 = 0, const XalanDOMChar* theParam3 = 0) const; /** * Given a target element, find the template that best matches in the given * stylesheet, using only imports * * @param executionContext current execution context * @param targetNode node that needs a rule * @param targetNodeType the type of targetNode * @param mode string indicating the mode * @return pointer to rule that best matches targetElem */ const ElemTemplate* findTemplateInImports( StylesheetExecutionContext& executionContext, XalanNode* targetNode, XalanNode::NodeType targetNodeType, const XalanQName& mode) const; /** * The full XSLT Namespace URI. To be replaced by the one actually * found. */ XalanDOMString m_XSLTNamespaceURI; /** * A vector of the -imported- XSL Stylesheets. */ StylesheetVectorType m_imports; StylesheetVectorType::size_type m_importsSize; /** * A stack to keep track of the result tree namespaces. */ NamespacesStackType m_namespaces; /** * A list of namespace declarations, * for mapping from prefix to namespace URI. */ NamespaceVectorType m_namespaceDecls; /** * Tells if the stylesheet is without an xsl:stylesheet and xsl:template * wrapper. */ bool m_isWrapperless; /** * The table of extension namespaces. */ ExtensionNamespacesMapType m_extensionNamespaces; /** * The first template of the template children. */ ElemTemplate* m_firstTemplate; /** * A stack of who's including who is needed in order to support "It is an * error if a stylesheet directly or indirectly includes itself." */ URLStackType m_includeStack; /** * Keyed on string macro names, and holding values that are macro elements * in the XSL DOM tree. Initialized in initMacroLookupTable, and used in * findNamedTemplate. */ ElemTemplateMapType m_namedTemplates; /** * Table for defined constants, keyed on the names. */ ElemVariableVectorType m_topLevelVariables; /** * The version of XSL that was declared. */ double m_XSLTVerDeclared; /** * This table is keyed on the target elements of patterns, and contains linked * lists of the actual patterns that match the target element to some degree * of specifity. */ PatternTableMapType m_elementPatternTable; const PatternTableMapType::const_iterator m_elementPatternTableEnd; PatternTableVectorType m_elementAnyPatternList; /** * This table is keyed on the target attributes of patterns, and contains linked * lists of the actual patterns that match the target attribute to some degree * of specifity. */ PatternTableMapType m_attributePatternTable; const PatternTableMapType::const_iterator m_attributePatternTableEnd; PatternTableVectorType m_attributeAnyPatternList; /** * These tables are for text, comment, root, and PI node templates. */ PatternTableVectorType m_textPatternList; PatternTableVectorType m_commentPatternList; PatternTableVectorType m_rootPatternList; PatternTableVectorType m_piPatternList; /** * This table is for patterns that match "node()". */ PatternTableVectorType m_nodePatternList; size_type m_patternCount; ElemDecimalFormatVectorType m_elemDecimalFormats; NamespacesHandler m_namespacesHandler; static const XalanDOMString s_emptyString; static const PatternTableVectorType s_emptyTemplateList; }; } #endif // XALAN_STYLESHEET_HEADER_GUARD