/* * 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_STYLESHEETHANDLER_HEADER_GUARD) #define XALAN_STYLESHEETHANDLER_HEADER_GUARD // Base include file. Must be first. #include "XSLTDefinitions.hpp" #include #include #include #include #include #include #include #include #include namespace XALAN_CPP_NAMESPACE { class ElemTemplate; class ElemTemplateElement; class ElemTextLiteral; class ExtensionNSHandler; class StylesheetConstructionContext; /** * This class processes a stylesheet via SAX events, and inits * the given stylesheet. If you need to alter the code in here, * it is not for the faint-of-heart, due to the state tracking * that has to be done due to the SAX event model. */ class XALAN_XSLT_EXPORT StylesheetHandler : public FormatterListener { public: typedef XalanVector ElemTemplateStackType; typedef XalanVector ElemTextLiteralStackType; typedef XalanVector BoolStackType; typedef XalanSet QNameSetType; typedef XalanVector > QNameSetVectorType; /** * Perform static initialization. See class XMLSupportInit. */ static void initialize(MemoryManager& theManager); /** * Perform static shut down. See class XMLSupportInit. */ static void terminate(); /** * Construct a StylesheetHandler ... it will add the DOM nodes * to the document fragment. */ StylesheetHandler( Stylesheet& stylesheetTree, StylesheetConstructionContext& constructionContext); MemoryManager& getMemoryManager() { return m_constructionContext.getMemoryManager(); } virtual ~StylesheetHandler(); /** * Receive notification of character data. * *

The Parser will call this method to report each chunk of * character data. SAX parsers may return all contiguous character * data in a single chunk, or they may split it into several * chunks; however, all of the characters in any single event * must come from the same external entity, so that the Locator * provides useful information.

* *

The application must not attempt to read from the array * outside of the specified range.

* *

Note that some parsers will report whitespace using the * ignorableWhitespace() method rather than this one (validating * parsers must do so).

* * @param chars pointer to characters from the XML document * @param length number of characters to read from the array * @exception SAXException * @see #ignorableWhitespace * @see org.xml.sax.Locator */ virtual void characters( const XMLCh* const chars, const size_type length); /** * Receive notification of character data. If available, when the * disable-output-escaping attribute is used, output raw text without * escaping. * * @param ch pointer to characters from the XML document * @param start start position in the array * @param length number of characters to read from the array * @exception SAXException */ virtual void charactersRaw( const XMLCh* const chars, const size_type length); /** * Receive notification of cdata. * *

The Parser will call this method to report each chunk of * character data. SAX parsers may return all contiguous character * data in a single chunk, or they may split it into several * chunks; however, all of the characters in any single event * must come from the same external entity, so that the Locator * provides useful information.

* *

The application must not attempt to read from the array * outside of the specified range.

* *

Note that some parsers will report whitespace using the * ignorableWhitespace() method rather than this one (validating * parsers must do so).

* * @param ch pointer to characters from the XML document * @param start start position in the array * @param length number of characters to read from the array * @exception SAXException * @see #ignorableWhitespace */ virtual void cdata( const XMLCh* const ch, const size_type length); /** * Receive notification of ignorable whitespace in element content. * *

Validating Parsers must use this method to report each chunk * of ignorable whitespace (see the W3C XML 1.0 recommendation, * section 2.10): non-validating parsers may also use this method * if they are capable of parsing and using content models.

* *

SAX parsers may return all contiguous whitespace in a single * chunk, or they may split it into several chunks; however, all of * the characters in any single event must come from the same * external entity, so that the Locator provides useful * information.

* *

The application must not attempt to read from the array * outside of the specified range.

* * @param chars characters from the XML document * @param start start position in the array * @param length number of characters to read from the array * @exception SAXException * @see #characters */ virtual void ignorableWhitespace( const XMLCh* const chars, const size_type length); /** * Receive notification of a processing instruction. * *

The Parser will invoke this method once for each processing * instruction found: note that processing instructions may occur * before or after the main document element.

* *

A SAX parser should never report an XML declaration (XML 1.0, * section 2.8) or a text declaration (XML 1.0, section 4.3.1) * using this method.

* * @param target pointer to processing instruction target * @param data pointer to processing instruction data, or null if none * was supplied * @exception SAXException */ virtual void processingInstruction (const XMLCh* const target, const XMLCh* const data); /** * Called when a Comment is to be constructed. * * @param data comment data * @exception SAXException */ virtual void comment(const XMLCh* const data); /** * Receive notification of a entityReference. * * @param data pointer to characters from the XML document * @exception SAXException */ virtual void entityReference(const XMLCh* const data); // These methods are inherited DocumentHandler ... // $$$ Theoretically, shouldn't need javadoc for these, since they are // inherited from DocumentHandler, but let's leave them in for now -- JMD /** * Receive an object for locating the origin of SAX document events. * *

SAX parsers are strongly encouraged (though not absolutely * required) to supply a locator: if it does so, it must supply * the locator to the application by invoking this method before * invoking any of the other methods in the DocumentHandler * interface.

* *

The locator allows the application to determine the end * position of any document-related event, even if the parser is * not reporting an error. Typically, the application will * use this information for reporting its own errors (such as * character content that does not match an application's * business rules). The information returned by the locator * is probably not sufficient for use with a search engine.

* *

Note that the locator will return correct information only * during the invocation of the events in this interface. The * application should not attempt to use it at any other time.

* * @param locator object that can return the location of * any SAX document event. * @see org.xml.sax.Locator */ virtual void setDocumentLocator(const Locator* const locator); /** * Receive notification of the beginning of a document. * *

The SAX parser will invoke this method only once, before any * other methods in this interface or in DTDHandler (except for * setDocumentLocator).

* * @exception SAXException */ virtual void startDocument(); /** * Receive notification of the end of a document. * *

The SAX parser will invoke this method only once, and it will * be the last method invoked during the parse. The parser shall * not invoke this method until it has either abandoned parsing * (because of an unrecoverable error) or reached the end of * input.

* * @exception SAXException */ virtual void endDocument(); /** * Receive notification of the beginning of an element. * *

The Parser will invoke this method at the beginning of every * element in the XML document; there will be a corresponding * endElement() event for every startElement() event (even when the * element is empty). All of the element's content will be * reported, in order, before the corresponding endElement() * event.

* *

If the element name has a namespace prefix, the prefix will * still be attached. Note that the attribute list provided will * contain only attributes with explicit values (specified or * defaulted): #IMPLIED attributes will be omitted.

* * @param name element type name * @param atts attributes attached to the element, if any * @exception SAXException * @see #endElement * @see org.xml.sax.AttributeList */ virtual void startElement(const XMLCh* const name, AttributeListType& attrs); /** * Receive notification of the end of an element. * *

The SAX parser will invoke this method at the end of every * element in the XML document; there will be a corresponding * startElement() event for every endElement() event (even when the * element is empty).

* *

If the element name has a namespace prefix, the prefix will * still be attached to the name.

* * @param name element type name * @exception SAXException */ virtual void endElement(const XMLCh* const name); /** * This method allows the user installed Document Handler to 'reset' * itself, freeing all the memory resources. The scanner calls this * method before starting a new parse event. */ virtual void resetDocument(); protected: /** * See if this is a xmlns attribute, and, if so, process it. * * @param attrName Qualified name of attribute. * @param atts The attribute list where the element comes from (not used at * this time). * @param which The 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); /** * Tell whether or not this is a xml:space attribute and, if so, process it. * * @param elementName The name of the element that owns the attribute * @param aname The name of the attribute in question. * @param atts The attribute list that owns the attribute. * @param which The index of the attribute into the attribute list. * @param locator A Locator instance for error reporting. * @param fPreserve set to true if the attribute value is "preserve" * @return True if this is a xml:space attribute. */ bool processSpaceAttr( const XalanDOMChar* elementName, const XalanDOMChar* aname, const AttributeListType& atts, XalanSize_t which, const Locator* locator, bool& fPreserve); /** * Tell whether or not this is a xml:space attribute and, if so, process it. * * @param elementName The name of the element that owns the attributes * @param atts The attribute list that owns the attribute. * @param locator A Locator instance for error reporting. * @param fPreserve set to true if an xml:space attribute value is "preserve" * @return True if this is a xml:space attribute. */ bool processSpaceAttr( const XalanDOMChar* elementName, const AttributeListType& atts, const Locator* locator, bool& fPreserve); /** * Process xsl:import. */ void processImport( const XalanDOMChar* name, const AttributeListType& atts, const Locator* locator); /** * Process xsl:include. */ void processInclude( const XalanDOMChar* name, const AttributeListType& atts, const Locator* locator); void doCleanup(); private: enum { eElemEmptyAllocatorBlockSize = 10, eElemTextBlockSize = 10 }; // not implemented StylesheetHandler(const StylesheetHandler&); StylesheetHandler& operator=(const StylesheetHandler&); // Utility functions... void illegalAttributeError( const XalanDOMChar* theElementName, const XalanDOMChar* theAttributeName, const Locator* theLocator) const; void error( const XalanDOMChar* theMessage1, const XalanDOMChar* theMessage2, const Locator* theLocator) const; void error( const XalanDOMChar* theMessage1, const XalanDOMString& theMessage2, const Locator* theLocator) const; void error( const XalanDOMString& theMessage1, const XalanDOMChar* theMessage2, const Locator* theLocator) const; void error( const XalanDOMString& theMessage1, const XalanDOMString& theMessage2, const Locator* theLocator) const; void warn( const XalanDOMChar* theMessage1, const XalanDOMChar* theMessage2, const Locator* theLocator) const; void warn( const XalanDOMChar* theMessage1, const XalanDOMString& theMessage2, const Locator* theLocator) const; void warn( const XalanDOMString& theMessage, const Locator* theLocator) const; void error( const XalanDOMString& theMessage, const Locator* theLocator) const; void processText( const XMLCh* chars, size_type length); void accumulateText( const XMLCh* chars, size_type length); void processAccumulatedText(); void processTopLevelElement( const XalanDOMChar* name, const AttributeListType& atts, int xslToken, const Locator* locator, bool& fPreserveSpace, bool& fSpaceAttrProcessed); void processStylesheet( const XalanDOMChar* name, const AttributeListType& atts, const Locator* locator, bool& fPreserveSpace, bool& fSpaceAttrProcessed); void processPreserveStripSpace( const XalanDOMChar* name, const AttributeListType& atts, const Locator* locator, int xslToken); void appendChildElementToParent( ElemTemplateElement* elem, const Locator* locator); void appendChildElementToParent( ElemTemplateElement* parent, ElemTemplateElement* elem); void appendChildElementToParent( ElemTemplateElement* parent, ElemTemplateElement* elem, const Locator* locator); bool inExtensionElement() const; void processExtensionElement( const XalanDOMChar* name, const XalanDOMString& localName, const AttributeListType& atts, const Locator* locator); void checkForOrAddVariableName( const XalanQName& theVariableName, const Locator* theLocator); // Data members... /** * The owning stylesheet. */ Stylesheet& m_stylesheet; /** * The construction context. */ StylesheetConstructionContext& m_constructionContext; /** * An allocator for ElemEmpty instances. */ XalanElemEmptyAllocator m_elemEmptyAllocator; /** * An allocator for ElemText instances. */ XalanElemTextAllocator m_elemTextAllocator; /** * The stack of elements, pushed and popped as events occur. */ ElemTemplateStackType m_elemStack; /** * Need to keep a stack of found whitespace elements so that * whitespace elements next to non-whitespace elements can * be merged. For instance: <out> <![CDATA[test]]> </out> */ ElemTextLiteralStackType m_whiteSpaceElems; /** * The current template. */ ElemTemplateElement* m_pTemplate; class LastPoppedHolder { public: LastPoppedHolder(StylesheetHandler& theStylesheetHandler) : m_stylesheetHandler(theStylesheetHandler), m_lastPopped(0) { } ~LastPoppedHolder() { cleanup(); } ElemTemplateElement* operator->() const { return m_lastPopped; } bool operator==(ElemTemplateElement* theRHS) { return m_lastPopped == theRHS; } bool operator!=(ElemTemplateElement* theRHS) { return m_lastPopped != theRHS; } void operator=(ElemTemplateElement* theRHS) { if (theRHS != m_lastPopped) { cleanup(); m_lastPopped = theRHS; } } void swap(LastPoppedHolder& theOther) { ElemTemplateElement* const theTemp = m_lastPopped; m_lastPopped = theOther.m_lastPopped; theOther.m_lastPopped = theTemp; } ElemTemplateElement* get() const { return m_lastPopped; } private: void set(ElemTemplateElement* theNewElement) { if (theNewElement != m_lastPopped) { cleanup(); m_lastPopped = theNewElement; } } // Not implemented... LastPoppedHolder& operator=(const LastPoppedHolder&); LastPoppedHolder(const LastPoppedHolder&); // Helper functions... void cleanup(); // Data members... StylesheetHandler& m_stylesheetHandler; ElemTemplateElement* m_lastPopped; }; friend class LastPoppedHolder; /** * Manages the last element popped from the stack. */ LastPoppedHolder m_lastPopped; /** * True if the process is in a template context. */ bool m_inTemplate; /** * True if the stylesheet element was found, or if it was determined that * the stylesheet is wrapperless. */ bool m_foundStylesheet; /** * Flag to let us know when we've found an element inside the * stylesheet that is not an xsl:import, so we can restrict imports * to being the first elements. */ bool m_foundNotImport; XalanDOMString m_elementLocalName; /** * Accumulate character buffer to create contiguous character data * where possible. */ XalanDOMString m_accumulateText; XalanDOMString m_includeBase; BoolStackType m_inExtensionElementStack; BoolStackType m_preserveSpaceStack; // Note that these variables must not be saved by // PushPopIncludeState... unsigned long m_locatorsPushed; QNameSetType m_globalVariableNames; enum { eVariablesStackDefault = 20 }; QNameSetVectorType m_inScopeVariableNamesStack; /** * Init the wrapperless template */ ElemTemplateElement* initWrapperless( const XalanDOMChar* name, const AttributeListType& atts, const Locator* locator); const XalanDOMString* getNamespaceFromStack(const XalanDOMChar* theName, XalanDOMString& theBuffer) const; const XalanDOMString* getNamespaceForPrefixFromStack(const XalanDOMString& thePrefix) const; class PushPopIncludeState; friend class StylesheetHandler::PushPopIncludeState; class PushPopIncludeState { public: PushPopIncludeState(StylesheetHandler& theHandler); ~PushPopIncludeState(); private: StylesheetHandler& m_handler; ElemTemplateStackType m_elemStack; ElemTemplateElement* const m_pTemplate; LastPoppedHolder m_lastPopped; const bool m_inTemplate; const bool m_foundStylesheet; const XalanDOMString m_XSLNameSpaceURL; const bool m_foundNotImport; Stylesheet::NamespaceVectorType m_namespaceDecls; Stylesheet::NamespacesStackType m_namespaces; NamespacesHandler m_namespacesHandler; BoolStackType m_inExtensionElementStack; BoolStackType m_preserveSpaceStack; }; static const XalanDOMString s_emptyString; }; } #endif // XALAN_STYLESHEETHANDLER_HEADER_GUARD