📄 jspdocumentparser.java
字号:
/*
* 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.
*/
package org.apache.jasper.compiler;
import java.io.CharArrayWriter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.jar.JarFile;
import javax.servlet.jsp.tagext.TagFileInfo;
import javax.servlet.jsp.tagext.TagInfo;
import javax.servlet.jsp.tagext.TagLibraryInfo;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.apache.jasper.JasperException;
import org.apache.jasper.JspCompilationContext;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.ext.LexicalHandler;
import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.DefaultHandler;
/**
* Class implementing a parser for a JSP document, that is, a JSP page in XML
* syntax.
*
* @author Jan Luehe
* @author Kin-man Chung
*/
class JspDocumentParser
extends DefaultHandler
implements LexicalHandler, TagConstants {
private static final String JSP_VERSION = "version";
private static final String LEXICAL_HANDLER_PROPERTY =
"http://xml.org/sax/properties/lexical-handler";
private static final String JSP_URI = "http://java.sun.com/JSP/Page";
private static final EnableDTDValidationException ENABLE_DTD_VALIDATION_EXCEPTION =
new EnableDTDValidationException(
"jsp.error.enable_dtd_validation",
null);
private ParserController parserController;
private JspCompilationContext ctxt;
private PageInfo pageInfo;
private String path;
private StringBuffer charBuffer;
// Node representing the XML element currently being parsed
private Node current;
/*
* Outermost (in the nesting hierarchy) node whose body is declared to be
* scriptless. If a node's body is declared to be scriptless, all its
* nested nodes must be scriptless, too.
*/
private Node scriptlessBodyNode;
private Locator locator;
//Mark representing the start of the current element. Note
//that locator.getLineNumber() and locator.getColumnNumber()
//return the line and column numbers for the character
//immediately _following_ the current element. The underlying
//XMl parser eats white space that is not part of character
//data, so for Nodes that are not created from character data,
//this is the best we can do. But when we parse character data,
//we get an accurate starting location by starting with startMark
//as set by the previous element, and updating it as we advance
//through the characters.
private Mark startMark;
// Flag indicating whether we are inside DTD declarations
private boolean inDTD;
private boolean isValidating;
private ErrorDispatcher err;
private boolean isTagFile;
private boolean directivesOnly;
private boolean isTop;
// Nesting level of Tag dependent bodies
private int tagDependentNesting = 0;
// Flag set to delay incrmenting tagDependentNesting until jsp:body
// is first encountered
private boolean tagDependentPending = false;
/*
* Constructor
*/
public JspDocumentParser(
ParserController pc,
String path,
boolean isTagFile,
boolean directivesOnly) {
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;
}
/*
* Parses a JSP document by responding to SAX events.
*
* @throws JasperException
*/
public static Node.Nodes parse(
ParserController pc,
String path,
JarFile jarFile,
Node parent,
boolean isTagFile,
boolean directivesOnly,
String pageEnc,
String jspConfigPageEnc,
boolean isEncodingSpecifiedInProlog,
boolean isBomPresent)
throws JasperException {
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);
dummyRoot.setIsBomPresent(isBomPresent);
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());
}
// 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;
}
/*
* Processes the given list of included files.
*
* This is used to implement the include-prelude and include-coda
* subelements of the jsp-config element in web.xml
*/
private void addInclude(Node parent, List files) throws SAXException {
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);
}
}
}
/*
* Receives notification of the start of an element.
*
* This method assigns the given tag attributes to one of 3 buckets:
*
* - "xmlns" attributes that represent (standard or custom) tag libraries.
* - "xmlns" attributes that do not represent tag libraries.
* - all remaining attributes.
*
* For each "xmlns" attribute that represents a custom tag library, the
* corresponding TagLibraryInfo object is added to the set of custom
* tag libraries.
*/
public void startElement(
String uri,
String localName,
String qName,
Attributes attrs)
throws SAXException {
AttributesImpl taglibAttrs = null;
AttributesImpl nonTaglibAttrs = null;
AttributesImpl nonTaglibXmlnsAttrs = null;
processChars();
checkPrefixes(uri, qName, attrs);
if (directivesOnly &&
!(JSP_URI.equals(uri) && localName.startsWith(DIRECTIVE_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) &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -