FileDocCategorySizeDatePackage
JspDocumentParser.javaAPI DocGlassfish v2 API52265Fri May 04 22:32:52 BST 2007org.apache.jasper.compiler

JspDocumentParser

public class JspDocumentParser extends DefaultHandler implements TagConstants, LexicalHandler
Class implementing a parser for a JSP document, that is, a JSP page in XML syntax.
author
Jan Luehe
author
Kin-man Chung

Fields Summary
private static final String
JSP_VERSION
private static final String
LEXICAL_HANDLER_PROPERTY
private static final String
JSP_URI
private static final EnableDTDValidationException
ENABLE_DTD_VALIDATION_EXCEPTION
private ParserController
parserController
private org.apache.jasper.JspCompilationContext
ctxt
private PageInfo
pageInfo
private String
path
private StringBuffer
charBuffer
private Node
current
private Node
scriptlessBodyNode
private Locator
locator
private Mark
startMark
private boolean
inDTD
private boolean
isValidating
private ErrorDispatcher
err
private boolean
isTagFile
private boolean
directivesOnly
private boolean
isTop
private int
tagDependentNesting
private boolean
tagDependentPending
Constructors Summary
public JspDocumentParser(ParserController pc, String path, boolean isTagFile, boolean directivesOnly)


    /*
     * Constructor
     */
     
         
         
         
          
        this.parserController = pc;
        this.ctxt = pc.getJspCompilationContext();
        this.pageInfo = pc.getCompiler().getPageInfo();
        this.err = pc.getCompiler().getErrorDispatcher();
        this.path = path;
        this.isTagFile = isTagFile;
        this.directivesOnly = directivesOnly;
        this.isTop = true;
    
Methods Summary
private voidaddInclude(Node parent, java.util.List files)

        if (files != null) {
            Iterator iter = files.iterator();
            while (iter.hasNext()) {
                String file = (String)iter.next();
                AttributesImpl attrs = new AttributesImpl();
                attrs.addAttribute("", "file", "file", "CDATA", file);

                // Create a dummy Include directive node
                    Node includeDir =
                        new Node.IncludeDirective(attrs, null, // XXX
    parent);
                processIncludeDirective(file, includeDir);
            }
        }
    
private voidaddTaglibInfo(java.lang.String prefix, java.lang.String uri)


        if (uri.startsWith(URN_JSPTAGDIR)) {
            // uri (of the form "urn:jsptagdir:path") references tag file dir
            String tagdir = uri.substring(URN_JSPTAGDIR.length());
            TagLibraryInfo taglibInfo = new ImplicitTagLibraryInfo(
                    ctxt,
                    parserController,
                    prefix,
                    tagdir,
                    err);
            if (pageInfo.getTaglib(uri) == null) {
                pageInfo.addTaglib(uri, taglibInfo);
            }
            pageInfo.pushPrefixMapping(prefix, uri);

        } else {
            // uri references TLD file
            boolean isPlainUri = false;
            if (uri.startsWith(TagConstants.URN_JSPTLD)) {
                uri = uri.substring(TagConstants.URN_JSPTLD.length());
            } else {
                isPlainUri = true;
            }

            // START GlassFish 750
            ConcurrentHashMap<String, TagLibraryInfoImpl> taglibs =
                ctxt.getTaglibs();
            TagLibraryInfoImpl taglibInfo = taglibs.get(uri);
            if (taglibInfo == null) {
                synchronized (taglibs) {
                    taglibInfo = taglibs.get(uri);
                    if (taglibInfo == null) {
            // END GlassFish 750            
                        String[] location = ctxt.getTldLocation(uri);
                        if (location != null || !isPlainUri) {
                            /*
                             * If the uri value is a plain uri, a translation
                             * error must not be generated if the uri is not
                             * found in the taglib map.
                             * Instead, any actions in the namespace defined
                             * by the uri value must be treated as
                             * uninterpreted.
                             */
                            taglibInfo =
                                new TagLibraryInfoImpl(
                                    ctxt,
                                    parserController,
                                    prefix,
                                    uri,
                                    location,
                                    err);
                            // START GlassFish 750
                            ctxt.addTaglib(uri, taglibInfo);
                            pageInfo.addTaglib(uri, taglibInfo);
                            // END GlassFish 750
                        }
            // START GlassFish 750
                    }
                }
            }
            // END GlassFish 750

            if (taglibInfo != null) {
                if (pageInfo.getTaglib(uri) == null) {
                    pageInfo.addTaglib(uri,
                                       new TagLibraryInfoImpl(prefix,
                                                              uri,
                                                              taglibInfo,
                                                              pageInfo));
                }
                pageInfo.pushPrefixMapping(prefix, uri);
            } else {
                pageInfo.pushPrefixMapping(prefix, null);
            }
        }
    
public voidcharacters(char[] buf, int offset, int len)


        if (charBuffer == null) {
            charBuffer = new StringBuffer();
        }
        charBuffer.append(buf, offset, len);
    
private voidcheckPrefix(java.lang.String uri, java.lang.String qName)


        int index = qName.indexOf(':");
        if (index != -1) {
            String prefix = qName.substring(0, index);
            pageInfo.addPrefix(prefix);
            if ("jsp".equals(prefix) && !JSP_URI.equals(uri)) {
                pageInfo.setIsJspPrefixHijacked(true);
            }
        }
    
private voidcheckPrefixes(java.lang.String uri, java.lang.String qName, org.xml.sax.Attributes attrs)


        checkPrefix(uri, qName);

        int len = attrs.getLength();
        for (int i = 0; i < len; i++) {
            checkPrefix(attrs.getURI(i), attrs.getQName(i));
        }
    
private voidcheckScriptingBody(Node.ScriptingElement scriptingElem)

        Node.Nodes body = scriptingElem.getBody();
        if (body != null) {
            int size = body.size();
            for (int i = 0; i < size; i++) {
                Node n = body.getNode(i);
                if (!(n instanceof Node.TemplateText)) {
                    String elemType = SCRIPTLET_ACTION;
                    if (scriptingElem instanceof Node.Declaration)
                        elemType = DECLARATION_ACTION;
                    if (scriptingElem instanceof Node.Expression)
                        elemType = EXPRESSION_ACTION;
                    String msg =
                        Localizer.getMessage(
                            "jsp.error.parse.xml.scripting.invalid.body",
                            elemType);
                    throw new SAXException(msg);
                }
            }
        }
    
public voidcomment(char[] buf, int offset, int len)


        processChars();  // Flush char buffer and remove white spaces

        // ignore comments in the DTD
        if (!inDTD) {
            startMark =
                new Mark(
                    ctxt,
                    path,
                    locator.getLineNumber(),
                    locator.getColumnNumber());
            new Node.Comment(new String(buf, offset, len), startMark, current);
        }
    
public voidendCDATA()

        processChars();  // Flush char buffer and remove white spaces
    
public voidendDTD()

        inDTD = false;
    
public voidendElement(java.lang.String uri, java.lang.String localName, java.lang.String qName)


        processChars();

        if (directivesOnly &&
            !(JSP_URI.equals(uri) && localName.startsWith(DIRECTIVE_ACTION))) {
            return;
        }

        if (current instanceof Node.NamedAttribute) {
            boolean isTrim = ((Node.NamedAttribute)current).isTrim();
            Node.Nodes subElems = ((Node.NamedAttribute)current).getBody();
            for (int i = 0; subElems != null && i < subElems.size(); i++) {
                Node subElem = subElems.getNode(i);
                if (!(subElem instanceof Node.TemplateText)) {
                    continue;
                }
                // Ignore any whitespace (including spaces, carriage returns,
                // line feeds, and tabs, that appear at the beginning and at
                // the end of the body of the <jsp:attribute> action, if the
                // action's 'trim' attribute is set to TRUE (default).
                // In addition, any textual nodes in the <jsp:attribute> that
                // have only white space are dropped from the document, with
                // the exception of leading and trailing white-space-only
                // textual nodes in a <jsp:attribute> whose 'trim' attribute
                // is set to FALSE, which must be kept verbatim.
                if (i == 0) {
                    if (isTrim) {
                        ((Node.TemplateText)subElem).ltrim();
                    }
                } else if (i == subElems.size() - 1) {
                    if (isTrim) {
                        ((Node.TemplateText)subElem).rtrim();
                    }
                } else {
                    if (((Node.TemplateText)subElem).isAllSpace()) {
                        subElems.remove(subElem);
                    }
                }
            }
        } else if (current instanceof Node.ScriptingElement) {
            checkScriptingBody((Node.ScriptingElement)current);
        }

        if ( isTagDependent(current)) {
            tagDependentNesting--;
        }

        if (scriptlessBodyNode != null
                && current.equals(scriptlessBodyNode)) {
            scriptlessBodyNode = null;
        }

        if (current.getParent() != null) {
            current = current.getParent();
        }
    
public voidendEntity(java.lang.String name)

        // do nothing
    
public voidendPrefixMapping(java.lang.String prefix)


        if (directivesOnly) {
            String uri = pageInfo.getURI(prefix);
            if (!JSP_URI.equals(uri)) {
                return;
            }
        }

        pageInfo.popPrefixMapping(prefix);
    
public voiderror(org.xml.sax.SAXParseException e)

        throw e;
    
public voidfatalError(org.xml.sax.SAXParseException e)

        throw e;
    
private static java.lang.StringgetBodyType(Node.CustomTag custom)


        if (custom.getTagInfo() != null) {
            return custom.getTagInfo().getBodyContent();
        }

        return custom.getTagFileInfo().getTagInfo().getBodyContent();
    
private static javax.xml.parsers.SAXParsergetSAXParser(boolean validating, org.apache.jasper.compiler.JspDocumentParser jspDocParser)


        SAXParserFactory factory = SAXParserFactory.newInstance();
        factory.setNamespaceAware(true);

        // Preserve xmlns attributes
        factory.setFeature(
            "http://xml.org/sax/features/namespace-prefixes",
            true);
        factory.setFeature(
            "http://xml.org/sax/features/validation",
            validating);

        // Configure the parser
        SAXParser saxParser = factory.newSAXParser();
        XMLReader xmlReader = saxParser.getXMLReader();
        xmlReader.setProperty(LEXICAL_HANDLER_PROPERTY, jspDocParser);
        xmlReader.setErrorHandler(jspDocParser);

        return saxParser;
    
private booleanisTagDependent(Node n)


        if (n instanceof Node.CustomTag) {
            String bodyType = getBodyType((Node.CustomTag) n);
            return
                TagInfo.BODY_CONTENT_TAG_DEPENDENT.equalsIgnoreCase(bodyType);
        }
        return false;
    
public static Node.Nodesparse(ParserController pc, java.lang.String path, java.util.jar.JarFile jarFile, Node parent, boolean isTagFile, boolean directivesOnly, java.lang.String pageEnc, java.lang.String jspConfigPageEnc, boolean isEncodingSpecifiedInProlog)


        JspDocumentParser jspDocParser =
            new JspDocumentParser(pc, path, isTagFile, directivesOnly);
        Node.Nodes pageNodes = null;

        try {

            // Create dummy root and initialize it with given page encodings
            Node.Root dummyRoot = new Node.Root(null, parent, true);
            dummyRoot.setPageEncoding(pageEnc);
            dummyRoot.setJspConfigPageEncoding(jspConfigPageEnc);
            dummyRoot.setIsEncodingSpecifiedInProlog(
                isEncodingSpecifiedInProlog);
            jspDocParser.current = dummyRoot;
            if (parent == null) {
                jspDocParser.addInclude(
                    dummyRoot,
                    jspDocParser.pageInfo.getIncludePrelude());
            } else {
                jspDocParser.isTop = false;
            }

            // Parse the input
            SAXParser saxParser = getSAXParser(false, jspDocParser);
            InputStream inStream = null;
            try {
                inStream = JspUtil.getInputStream(path, jarFile,
                                                  jspDocParser.ctxt,
                                                  jspDocParser.err);
                saxParser.parse(new InputSource(inStream), jspDocParser);
            } catch (EnableDTDValidationException e) {
                saxParser = getSAXParser(true, jspDocParser);
                jspDocParser.isValidating = true;
                if (inStream != null) {
                    try {
                        inStream.close();
                    } catch (Exception any) {
                    }
                }
                inStream = JspUtil.getInputStream(path, jarFile,
                                                  jspDocParser.ctxt,
                                                  jspDocParser.err);
                saxParser.parse(new InputSource(inStream), jspDocParser);
            } finally {
                if (inStream != null) {
                    try {
                        inStream.close();
                    } catch (Exception any) {
                    }
                }
            }

            if (parent == null) {
                jspDocParser.addInclude(
                    dummyRoot,
                    jspDocParser.pageInfo.getIncludeCoda());
                jspDocParser.pageInfo.setRootPath(path);
            }

            // Create Node.Nodes from dummy root
            pageNodes = new Node.Nodes(dummyRoot);

        } catch (IOException ioe) {
            jspDocParser.err.jspError("jsp.error.data.file.read", path, ioe);
        } catch (SAXParseException e) {
            jspDocParser.err.jspError
                (new Mark(jspDocParser.ctxt, path, e.getLineNumber(),
                          e.getColumnNumber()),
                 e.getMessage());
        } catch (Exception e) {
            jspDocParser.err.jspError(e);
        }

        return pageNodes;
    
private NodeparseCustomAction(java.lang.String qName, java.lang.String localName, java.lang.String uri, org.xml.sax.Attributes nonTaglibAttrs, org.xml.sax.Attributes nonTaglibXmlnsAttrs, org.xml.sax.Attributes taglibAttrs, Mark start, Node parent)


        if (uri.startsWith(TagConstants.URN_JSPTLD)) {
            uri = uri.substring(TagConstants.URN_JSPTLD.length());
        }

        // Check if this is a user-defined (custom) tag
        TagLibraryInfo tagLibInfo = pageInfo.getTaglib(uri);
        if (tagLibInfo == null) {
            return null;
        }

        TagInfo tagInfo = tagLibInfo.getTag(localName);
        TagFileInfo tagFileInfo = tagLibInfo.getTagFile(localName);
        if (tagInfo == null && tagFileInfo == null) {
            throw new SAXException(
                Localizer.getMessage("jsp.error.xml.bad_tag", localName, uri));
        }
        Class tagHandlerClass = null;
        if (tagInfo != null) {
            String handlerClassName = tagInfo.getTagClassName();
            try {
                tagHandlerClass =
                    ctxt.getClassLoader().loadClass(handlerClassName);
            } catch (Exception e) {
                throw new SAXException(
                    Localizer.getMessage("jsp.error.loadclass.taghandler",
                                         handlerClassName,
                                         qName),
                    e);
            }
        }

        String prefix = "";
        int colon = qName.indexOf(':");
        if (colon != -1) {
            prefix = qName.substring(0, colon);
        }

        Node.CustomTag ret = null;
        if (tagInfo != null) {
            ret =
                new Node.CustomTag(
                    tagLibInfo.getRequiredVersion(),
                    qName,
                    prefix,
                    localName,
                    uri,
                    nonTaglibAttrs,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    parent,
                    tagInfo,
                    tagHandlerClass);
        } else {
            ret =
                new Node.CustomTag(
                    tagLibInfo.getRequiredVersion(),
                    qName,
                    prefix,
                    localName,
                    uri,
                    nonTaglibAttrs,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    parent,
                    tagFileInfo);
        }

        return ret;
    
private NodeparseStandardAction(java.lang.String qName, java.lang.String localName, org.xml.sax.Attributes nonTaglibAttrs, org.xml.sax.Attributes nonTaglibXmlnsAttrs, org.xml.sax.Attributes taglibAttrs, Mark start, Node parent)


        Node node = null;

        if (localName.equals(ROOT_ACTION)) {
            if (!(current instanceof Node.Root)) {
                throw new SAXParseException(
                    Localizer.getMessage("jsp.error.nested_jsproot"),
                    locator);
            }
            node =
                new Node.JspRoot(
                    qName,
                    nonTaglibAttrs,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    current);
            if (isTop) {
                pageInfo.setHasJspRoot(true);
            }
        } else if (localName.equals(PAGE_DIRECTIVE_ACTION)) {
            if (isTagFile) {
                throw new SAXParseException(
                    Localizer.getMessage(
                        "jsp.error.action.istagfile",
                        localName),
                    locator);
            }
            node =
                new Node.PageDirective(
                    qName,
                    nonTaglibAttrs,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    current);
            String imports = nonTaglibAttrs.getValue("import");
            // There can only be one 'import' attribute per page directive
            if (imports != null) {
                ((Node.PageDirective)node).addImport(imports);
            }
        } else if (localName.equals(INCLUDE_DIRECTIVE_ACTION)) {
            node =
                new Node.IncludeDirective(
                    qName,
                    nonTaglibAttrs,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    current);
            processIncludeDirective(nonTaglibAttrs.getValue("file"), node);
        } else if (localName.equals(DECLARATION_ACTION)) {
            if (scriptlessBodyNode != null) {
                // We're nested inside a node whose body is
                // declared to be scriptless
                throw new SAXParseException(
                    Localizer.getMessage(
                        "jsp.error.no.scriptlets",
                        localName),
                    locator);
            }
            node =
                new Node.Declaration(
                    qName,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    current);
        } else if (localName.equals(SCRIPTLET_ACTION)) {
            if (scriptlessBodyNode != null) {
                // We're nested inside a node whose body is
                // declared to be scriptless
                throw new SAXParseException(
                    Localizer.getMessage(
                        "jsp.error.no.scriptlets",
                        localName),
                    locator);
            }
            node =
                new Node.Scriptlet(
                    qName,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    current);
        } else if (localName.equals(EXPRESSION_ACTION)) {
            if (scriptlessBodyNode != null) {
                // We're nested inside a node whose body is
                // declared to be scriptless
                throw new SAXParseException(
                    Localizer.getMessage(
                        "jsp.error.no.scriptlets",
                        localName),
                    locator);
            }
            node =
                new Node.Expression(
                    qName,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    current);
        } else if (localName.equals(USE_BEAN_ACTION)) {
            node =
                new Node.UseBean(
                    qName,
                    nonTaglibAttrs,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    current);
        } else if (localName.equals(SET_PROPERTY_ACTION)) {
            node =
                new Node.SetProperty(
                    qName,
                    nonTaglibAttrs,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    current);
        } else if (localName.equals(GET_PROPERTY_ACTION)) {
            node =
                new Node.GetProperty(
                    qName,
                    nonTaglibAttrs,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    current);
        } else if (localName.equals(INCLUDE_ACTION)) {
            node =
                new Node.IncludeAction(
                    qName,
                    nonTaglibAttrs,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    current);
        } else if (localName.equals(FORWARD_ACTION)) {
            node =
                new Node.ForwardAction(
                    qName,
                    nonTaglibAttrs,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    current);
        } else if (localName.equals(PARAM_ACTION)) {
            node =
                new Node.ParamAction(
                    qName,
                    nonTaglibAttrs,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    current);
        } else if (localName.equals(PARAMS_ACTION)) {
            node =
                new Node.ParamsAction(
                    qName,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    current);
        } else if (localName.equals(PLUGIN_ACTION)) {
            node =
                new Node.PlugIn(
                    qName,
                    nonTaglibAttrs,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    current);
        } else if (localName.equals(TEXT_ACTION)) {
            node =
                new Node.JspText(
                    qName,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    current);
        } else if (localName.equals(BODY_ACTION)) {
            node =
                new Node.JspBody(
                    qName,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    current);
        } else if (localName.equals(ATTRIBUTE_ACTION)) {
            node =
                new Node.NamedAttribute(
                    qName,
                    nonTaglibAttrs,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    current);
        } else if (localName.equals(OUTPUT_ACTION)) {
            node =
                new Node.JspOutput(
                    qName,
                    nonTaglibAttrs,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    current);
        } else if (localName.equals(TAG_DIRECTIVE_ACTION)) {
            if (!isTagFile) {
                throw new SAXParseException(
                    Localizer.getMessage(
                        "jsp.error.action.isnottagfile",
                        localName),
                    locator);
            }
            node =
                new Node.TagDirective(
                    qName,
                    nonTaglibAttrs,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    current);
            String imports = nonTaglibAttrs.getValue("import");
            // There can only be one 'import' attribute per tag directive
            if (imports != null) {
                ((Node.TagDirective)node).addImport(imports);
            }
        } else if (localName.equals(ATTRIBUTE_DIRECTIVE_ACTION)) {
            if (!isTagFile) {
                throw new SAXParseException(
                    Localizer.getMessage(
                        "jsp.error.action.isnottagfile",
                        localName),
                    locator);
            }
            node =
                new Node.AttributeDirective(
                    qName,
                    nonTaglibAttrs,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    current);
        } else if (localName.equals(VARIABLE_DIRECTIVE_ACTION)) {
            if (!isTagFile) {
                throw new SAXParseException(
                    Localizer.getMessage(
                        "jsp.error.action.isnottagfile",
                        localName),
                    locator);
            }
            node =
                new Node.VariableDirective(
                    qName,
                    nonTaglibAttrs,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    current);
        } else if (localName.equals(INVOKE_ACTION)) {
            if (!isTagFile) {
                throw new SAXParseException(
                    Localizer.getMessage(
                        "jsp.error.action.isnottagfile",
                        localName),
                    locator);
            }
            node =
                new Node.InvokeAction(
                    qName,
                    nonTaglibAttrs,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    current);
        } else if (localName.equals(DOBODY_ACTION)) {
            if (!isTagFile) {
                throw new SAXParseException(
                    Localizer.getMessage(
                        "jsp.error.action.isnottagfile",
                        localName),
                    locator);
            }
            node =
                new Node.DoBodyAction(
                    qName,
                    nonTaglibAttrs,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    current);
        } else if (localName.equals(ELEMENT_ACTION)) {
            node =
                new Node.JspElement(
                    qName,
                    nonTaglibAttrs,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    current);
        } else if (localName.equals(FALLBACK_ACTION)) {
            node =
                new Node.FallBackAction(
                    qName,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    start,
                    current);
        } else {
            throw new SAXParseException(
                Localizer.getMessage(
                    "jsp.error.xml.badStandardAction",
                    localName),
                locator);
        }

        return node;
    
private voidprocessChars()


        if (charBuffer == null || directivesOnly) {
            return;
        }

        /*
         * JSP.6.1.1: All textual nodes that have only white space are to be
         * dropped from the document, except for nodes in a jsp:text element,
         * and any leading and trailing white-space-only textual nodes in a
         * jsp:attribute whose 'trim' attribute is set to FALSE, which are to
         * be kept verbatim.
         * JSP.6.2.3 defines white space characters.
         */
        boolean isAllSpace = true;
        if (!(current instanceof Node.JspText)
            && !(current instanceof Node.NamedAttribute)) {
            for (int i = 0; i < charBuffer.length(); i++) {
                if (!(charBuffer.charAt(i) == ' "
                    || charBuffer.charAt(i) == '\n"
                    || charBuffer.charAt(i) == '\r"
                    || charBuffer.charAt(i) == '\t")) {
                    isAllSpace = false;
                    break;
                }
            }
        }

        if (!isAllSpace && tagDependentPending) {
            tagDependentPending = false;
            tagDependentNesting++;
        }

        if (tagDependentNesting > 0) {
            if (charBuffer.length() > 0) {
                new Node.TemplateText(charBuffer.toString(), startMark, current);
            }
            startMark = new Mark(ctxt, path, locator.getLineNumber(),
                                 locator.getColumnNumber());
            charBuffer = null;
            return;
        }

        if ((current instanceof Node.JspText)
            || (current instanceof Node.NamedAttribute)
            || !isAllSpace) {

            int line = startMark.getLineNumber();
            int column = startMark.getColumnNumber();

            CharArrayWriter ttext = new CharArrayWriter();
            int lastCh = 0;
            for (int i = 0; i < charBuffer.length(); i++) {

                int ch = charBuffer.charAt(i);
                if (ch == '\n") {
                    column = 1;
                    line++;
                } else {
                    column++;
                }
                if ((lastCh == '$" || lastCh == '#") && ch == '{") {
                    if (ttext.size() > 0) {
                        new Node.TemplateText(
                            ttext.toString(),
                            startMark,
                            current);
                        ttext = new CharArrayWriter();
                        //We subtract two from the column number to
                        //account for the '${' that we've already parsed
                        startMark = new Mark(ctxt, path, line, column - 2);
                    }
                    ttext.write(lastCh);
                    ttext.write('{");
                    // following "${" to first unquoted "}"
                    i++;
                    boolean singleQ = false;
                    boolean doubleQ = false;
                    lastCh = 0;
                    for (;; i++) {
                        if (i >= charBuffer.length()) {
                            throw new SAXParseException(
                                Localizer.getMessage(
                                    "jsp.error.unterminated",
                                    lastCh=='$"? "${": "#{"),
                                locator);

                        }
                        ch = charBuffer.charAt(i);
                        if (ch == '\n") {
                            column = 1;
                            line++;
                        } else {
                            column++;
                        }
                        if (lastCh == '\\" && (singleQ || doubleQ)) {
                            ttext.write(ch);
                            lastCh = 0;
                            continue;
                        }
                        if (ch == '}") {
                            ttext.write('}");
                            new Node.ELExpression(
                                ttext.toString(),
                                startMark,
                                current);
                            ttext = new CharArrayWriter();
                            startMark = new Mark(ctxt, path, line, column);
                            break;
                        }
                        if (ch == '"")
                            doubleQ = !doubleQ;
                        else if (ch == '\'")
                            singleQ = !singleQ;

                        ttext.write(ch);
                        lastCh = ch;
                    }
                } else if (lastCh == '\\" && (ch == '$" || ch == '#")) {
                    ttext.write(ch);
                    ch = 0;  // Not start of EL anymore
                } else {
                    if (lastCh == '$" || lastCh == '#" || lastCh == '\\") {
                        ttext.write(lastCh);
                    }
                    if (ch != '$" && ch != '#" && ch != '\\") {
                        ttext.write(ch);
                    }
                }
                lastCh = ch;
            }
            if (lastCh == '$" || lastCh == '#" || lastCh == '\\") {
                ttext.write(lastCh);
            }
            if (ttext.size() > 0) {
                new Node.TemplateText(ttext.toString(), startMark, current);
            }
        }
        startMark = new Mark(ctxt, path, locator.getLineNumber(),
                             locator.getColumnNumber());

        charBuffer = null;
    
private voidprocessIncludeDirective(java.lang.String fname, Node parent)


        if (fname == null) {
            return;
        }

        try {
            parserController.parse(fname, parent, null);
        } catch (FileNotFoundException fnfe) {
            throw new SAXParseException(
                Localizer.getMessage("jsp.error.file.not.found", fname),
                locator,
                fnfe);
        } catch (Exception e) {
            throw new SAXException(e);
        }
    
public voidsetDocumentLocator(org.xml.sax.Locator locator)

        this.locator = locator;
    
public voidstartCDATA()


        processChars();  // Flush char buffer and remove white spaces
        startMark = new Mark(ctxt, path, locator.getLineNumber(),
                             locator.getColumnNumber());
    
public voidstartDTD(java.lang.String name, java.lang.String publicId, java.lang.String systemId)

        if (!isValidating) {
            fatalError(ENABLE_DTD_VALIDATION_EXCEPTION);
        }

        inDTD = true;
    
public voidstartElement(java.lang.String uri, java.lang.String localName, java.lang.String qName, org.xml.sax.Attributes attrs)


        AttributesImpl taglibAttrs = null;
        AttributesImpl nonTaglibAttrs = null;
        AttributesImpl nonTaglibXmlnsAttrs = null;

        processChars();

        checkPrefixes(uri, qName, attrs);

        if (directivesOnly &&
            !(JSP_URI.equals(uri) &&
                    (localName.startsWith(DIRECTIVE_ACTION)
                    || localName.startsWith(ROOT_ACTION)))) {
            return;
        }

        // jsp:text must not have any subelements
        if (JSP_URI.equals(uri) && TEXT_ACTION.equals(current.getLocalName())) {
            throw new SAXParseException(
                Localizer.getMessage("jsp.error.text.has_subelement"),
                locator);
        }

        startMark = new Mark(ctxt, path, locator.getLineNumber(),
                             locator.getColumnNumber());

        if (attrs != null) {
            /*
             * Notice that due to a bug in the underlying SAX parser, the
             * attributes must be enumerated in descending order. 
             */
            boolean isTaglib = false;
            for (int i = attrs.getLength() - 1; i >= 0; i--) {
                isTaglib = false;
                String attrQName = attrs.getQName(i);
                if (!attrQName.startsWith("xmlns")) {
                    if (nonTaglibAttrs == null) {
                        nonTaglibAttrs = new AttributesImpl();
                    }
                    nonTaglibAttrs.addAttribute(
                        attrs.getURI(i),
                        attrs.getLocalName(i),
                        attrs.getQName(i),
                        attrs.getType(i),
                        attrs.getValue(i));
                } else {
                    if (attrQName.startsWith("xmlns:jsp")) {
                        isTaglib = true;
                    } else {
                        String attrUri = attrs.getValue(i);
                        // TaglibInfo for this uri already established in
                        // startPrefixMapping
                        isTaglib = pageInfo.hasTaglib(attrUri);
                    }
                    if (isTaglib) {
                        if (taglibAttrs == null) {
                            taglibAttrs = new AttributesImpl();
                        }
                        taglibAttrs.addAttribute(
                            attrs.getURI(i),
                            attrs.getLocalName(i),
                            attrs.getQName(i),
                            attrs.getType(i),
                            attrs.getValue(i));
                    } else {
                        if (nonTaglibXmlnsAttrs == null) {
                            nonTaglibXmlnsAttrs = new AttributesImpl();
                        }
                        nonTaglibXmlnsAttrs.addAttribute(
                            attrs.getURI(i),
                            attrs.getLocalName(i),
                            attrs.getQName(i),
                            attrs.getType(i),
                            attrs.getValue(i));
                    }
                }
            }
        }

        Node node = null;

        if (tagDependentPending && JSP_URI.equals(uri) &&
                     localName.equals(BODY_ACTION)) {
            tagDependentPending = false;
            tagDependentNesting++;
            current =
                parseStandardAction(
                    qName,
                    localName,
                    nonTaglibAttrs,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    startMark,
                    current);
            return;
        }

        if (tagDependentPending && JSP_URI.equals(uri) &&
                     localName.equals(ATTRIBUTE_ACTION)) {
            current =
                parseStandardAction(
                    qName,
                    localName,
                    nonTaglibAttrs,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    startMark,
                    current);
            return;
        }

        if (tagDependentPending) {
            tagDependentPending = false;
            tagDependentNesting++;
        }

        if (tagDependentNesting > 0) {
            node =
                new Node.UninterpretedTag(
                    qName,
                    localName,
                    nonTaglibAttrs,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    startMark,
                    current);
        } else if (JSP_URI.equals(uri)) {
            node =
                parseStandardAction(
                    qName,
                    localName,
                    nonTaglibAttrs,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    startMark,
                    current);
        } else {
            node =
                parseCustomAction(
                    qName,
                    localName,
                    uri,
                    nonTaglibAttrs,
                    nonTaglibXmlnsAttrs,
                    taglibAttrs,
                    startMark,
                    current);
            if (node == null) {
                node =
                    new Node.UninterpretedTag(
                        qName,
                        localName,
                        nonTaglibAttrs,
                        nonTaglibXmlnsAttrs,
                        taglibAttrs,
                        startMark,
                        current);
            } else {
                // custom action
                String bodyType = getBodyType((Node.CustomTag) node);

                if (scriptlessBodyNode == null
                        && bodyType.equalsIgnoreCase(TagInfo.BODY_CONTENT_SCRIPTLESS)) {
                    scriptlessBodyNode = node;
                }
                else if (TagInfo.BODY_CONTENT_TAG_DEPENDENT.equalsIgnoreCase(bodyType)) {
                    tagDependentPending = true;
                }
            }
        }

        current = node;
    
public voidstartEntity(java.lang.String name)

        // do nothing
    
public voidstartPrefixMapping(java.lang.String prefix, java.lang.String uri)


        if (directivesOnly && !(JSP_URI.equals(uri))) {
            return;
        }

        try {
            addTaglibInfo(prefix, uri);
        } catch (JasperException je) {
            throw new SAXParseException(
                Localizer.getMessage("jsp.error.could.not.add.taglibraries"),
                locator,
                je);
        }