|
Tomcat example source code file (Parser.java)
The Tomcat Parser.java source code
/*
* 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.net.URL;
import java.util.Iterator;
import java.util.List;
import javax.servlet.jsp.tagext.TagAttributeInfo;
import javax.servlet.jsp.tagext.TagFileInfo;
import javax.servlet.jsp.tagext.TagInfo;
import javax.servlet.jsp.tagext.TagLibraryInfo;
import org.apache.jasper.Constants;
import org.apache.jasper.JasperException;
import org.apache.jasper.JspCompilationContext;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.AttributesImpl;
/**
* This class implements a parser for a JSP page (non-xml view). JSP page
* grammar is included here for reference. The token '#' that appears in the
* production indicates the current input token location in the production.
*
* @author Kin-man Chung
* @author Shawn Bayern
* @author Mark Roth
*/
class Parser implements TagConstants {
private ParserController parserController;
private JspCompilationContext ctxt;
private JspReader reader;
private String currentFile;
private Mark start;
private ErrorDispatcher err;
private int scriptlessCount;
private boolean isTagFile;
private boolean directivesOnly;
private URL jarFileUrl;
private PageInfo pageInfo;
// Virtual body content types, to make parsing a little easier.
// These are not accessible from outside the parser.
private static final String JAVAX_BODY_CONTENT_PARAM = "JAVAX_BODY_CONTENT_PARAM";
private static final String JAVAX_BODY_CONTENT_PLUGIN = "JAVAX_BODY_CONTENT_PLUGIN";
private static final String JAVAX_BODY_CONTENT_TEMPLATE_TEXT = "JAVAX_BODY_CONTENT_TEMPLATE_TEXT";
/**
* The constructor
*/
private Parser(ParserController pc, JspReader reader, boolean isTagFile,
boolean directivesOnly, URL jarFileUrl) {
this.parserController = pc;
this.ctxt = pc.getJspCompilationContext();
this.pageInfo = pc.getCompiler().getPageInfo();
this.err = pc.getCompiler().getErrorDispatcher();
this.reader = reader;
this.currentFile = reader.mark().getFile();
this.scriptlessCount = 0;
this.isTagFile = isTagFile;
this.directivesOnly = directivesOnly;
this.jarFileUrl = jarFileUrl;
start = reader.mark();
}
/**
* The main entry for Parser
*
* @param pc
* The ParseController, use for getting other objects in compiler
* and for parsing included pages
* @param reader
* To read the page
* @param parent
* The parent node to this page, null for top level page
* @return list of nodes representing the parsed page
*/
public static Node.Nodes parse(ParserController pc, JspReader reader,
Node parent, boolean isTagFile, boolean directivesOnly,
URL jarFileUrl, String pageEnc, String jspConfigPageEnc,
boolean isDefaultPageEncoding, boolean isBomPresent) throws JasperException {
Parser parser = new Parser(pc, reader, isTagFile, directivesOnly,
jarFileUrl);
Node.Root root = new Node.Root(reader.mark(), parent, false);
root.setPageEncoding(pageEnc);
root.setJspConfigPageEncoding(jspConfigPageEnc);
root.setIsDefaultPageEncoding(isDefaultPageEncoding);
root.setIsBomPresent(isBomPresent);
if (directivesOnly) {
parser.parseTagFileDirectives(root);
return new Node.Nodes(root);
}
// For the Top level page, add inlcude-prelude and include-coda
PageInfo pageInfo = pc.getCompiler().getPageInfo();
if (parent == null) {
parser.addInclude(root, pageInfo.getIncludePrelude());
}
while (reader.hasMoreInput()) {
parser.parseElements(root);
}
if (parent == null) {
parser.addInclude(root, pageInfo.getIncludeCoda());
}
Node.Nodes page = new Node.Nodes(root);
return page;
}
/**
* Attributes ::= (S Attribute)* S?
*/
Attributes parseAttributes() throws JasperException {
AttributesImpl attrs = new AttributesImpl();
reader.skipSpaces();
while (parseAttribute(attrs))
reader.skipSpaces();
return attrs;
}
/**
* Parse Attributes for a reader, provided for external use
*/
public static Attributes parseAttributes(ParserController pc,
JspReader reader) throws JasperException {
Parser tmpParser = new Parser(pc, reader, false, false, null);
return tmpParser.parseAttributes();
}
/**
* Attribute ::= Name S? Eq S? ( '"<%=' RTAttributeValueDouble | '"'
* AttributeValueDouble | "'<%=" RTAttributeValueSingle | "'"
* AttributeValueSingle } Note: JSP and XML spec does not allow while spaces
* around Eq. It is added to be backward compatible with Tomcat, and with
* other xml parsers.
*/
private boolean parseAttribute(AttributesImpl attrs) throws JasperException {
// Get the qualified name
String qName = parseName();
if (qName == null)
return false;
// Determine prefix and local name components
String localName = qName;
String uri = "";
int index = qName.indexOf(':');
if (index != -1) {
String prefix = qName.substring(0, index);
uri = pageInfo.getURI(prefix);
if (uri == null) {
err.jspError(reader.mark(),
"jsp.error.attribute.invalidPrefix", prefix);
}
localName = qName.substring(index + 1);
}
reader.skipSpaces();
if (!reader.matches("="))
err.jspError(reader.mark(), "jsp.error.attribute.noequal");
reader.skipSpaces();
char quote = (char) reader.nextChar();
if (quote != '\'' && quote != '"')
err.jspError(reader.mark(), "jsp.error.attribute.noquote");
String watchString = "";
if (reader.matches("<%="))
watchString = "%>";
watchString = watchString + quote;
String attrValue = parseAttributeValue(watchString);
attrs.addAttribute(uri, localName, qName, "CDATA", attrValue);
return true;
}
/**
* Name ::= (Letter | '_' | ':') (Letter | Digit | '.' | '_' | '-' | ':')*
*/
private String parseName() throws JasperException {
char ch = (char) reader.peekChar();
if (Character.isLetter(ch) || ch == '_' || ch == ':') {
StringBuffer buf = new StringBuffer();
buf.append(ch);
reader.nextChar();
ch = (char) reader.peekChar();
while (Character.isLetter(ch) || Character.isDigit(ch) || ch == '.'
|| ch == '_' || ch == '-' || ch == ':') {
buf.append(ch);
reader.nextChar();
ch = (char) reader.peekChar();
}
return buf.toString();
}
return null;
}
/**
* AttributeValueDouble ::= (QuotedChar - '"')* ('"' | <TRANSLATION_ERROR>)
* RTAttributeValueDouble ::= ((QuotedChar - '"')* - ((QuotedChar-'"')'%>"')
* ('%>"' | TRANSLATION_ERROR)
*/
private String parseAttributeValue(String watch) throws JasperException {
Mark start = reader.mark();
Mark stop = reader.skipUntilIgnoreEsc(watch);
if (stop == null) {
err.jspError(start, "jsp.error.attribute.unterminated", watch);
}
String ret = parseQuoted(reader.getText(start, stop));
if (watch.length() == 1) // quote
return ret;
// putback delimiter '<%=' and '%>', since they are needed if the
// attribute does not allow RTexpression.
return "<%=" + ret + "%>";
}
/**
* QuotedChar ::= ''' | '"' | '\\' | '\"' | "\'" | '\>' | '\$' |
* Char
*/
private String parseQuoted(String tx) {
StringBuffer buf = new StringBuffer();
int size = tx.length();
int i = 0;
while (i < size) {
char ch = tx.charAt(i);
if (ch == '&') {
if (i + 5 < size && tx.charAt(i + 1) == 'a'
&& tx.charAt(i + 2) == 'p' && tx.charAt(i + 3) == 'o'
&& tx.charAt(i + 4) == 's' && tx.charAt(i + 5) == ';') {
buf.append('\'');
i += 6;
} else if (i + 5 < size && tx.charAt(i + 1) == 'q'
&& tx.charAt(i + 2) == 'u' && tx.charAt(i + 3) == 'o'
&& tx.charAt(i + 4) == 't' && tx.charAt(i + 5) == ';') {
buf.append('"');
i += 6;
} else {
buf.append(ch);
++i;
}
} else if (ch == '\\' && i + 1 < size) {
ch = tx.charAt(i + 1);
if (ch == '\\' || ch == '\"' || ch == '\'' || ch == '>') {
buf.append(ch);
i += 2;
} else if (ch == '$') {
// Replace "\$" with some special char. XXX hack!
buf.append(Constants.ESC);
i += 2;
} else {
buf.append('\\');
++i;
}
} else {
buf.append(ch);
++i;
}
}
return buf.toString();
}
private String parseScriptText(String tx) {
CharArrayWriter cw = new CharArrayWriter();
int size = tx.length();
int i = 0;
while (i < size) {
char ch = tx.charAt(i);
if (i + 2 < size && ch == '%' && tx.charAt(i + 1) == '\\'
&& tx.charAt(i + 2) == '>') {
cw.write('%');
cw.write('>');
i += 3;
} else {
cw.write(ch);
++i;
}
}
cw.close();
return cw.toString();
}
/*
* Invokes parserController to parse the included page
*/
private void processIncludeDirective(String file, Node parent)
throws JasperException {
if (file == null) {
return;
}
try {
parserController.parse(file, parent, jarFileUrl);
} catch (FileNotFoundException ex) {
err.jspError(start, "jsp.error.file.not.found", file);
} catch (Exception ex) {
err.jspError(start, ex.getMessage());
}
}
/*
* Parses a page directive with the following syntax: PageDirective ::= ( S
* Attribute)*
*/
private void parsePageDirective(Node parent) throws JasperException {
Attributes attrs = parseAttributes();
Node.PageDirective n = new Node.PageDirective(attrs, start, parent);
/*
* A page directive may contain multiple 'import' attributes, each of
* which consists of a comma-separated list of package names. Store each
* list with the node, where it is parsed.
*/
for (int i = 0; i < attrs.getLength(); i++) {
if ("import".equals(attrs.getQName(i))) {
n.addImport(attrs.getValue(i));
}
}
}
/*
* Parses an include directive with the following syntax: IncludeDirective
* ::= ( S Attribute)*
*/
private void parseIncludeDirective(Node parent) throws JasperException {
Attributes attrs = parseAttributes();
// Included file expanded here
Node includeNode = new Node.IncludeDirective(attrs, start, parent);
processIncludeDirective(attrs.getValue("file"), includeNode);
}
/**
* Add a list of files. This is used for implementing include-prelude and
* include-coda of jsp-config element in web.xml
*/
private void addInclude(Node parent, List files) throws JasperException {
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 includeNode = new Node.IncludeDirective(attrs, reader
.mark(), parent);
processIncludeDirective(file, includeNode);
}
}
}
/*
* Parses a taglib directive with the following syntax: Directive ::= ( S
* Attribute)*
*/
private void parseTaglibDirective(Node parent) throws JasperException {
Attributes attrs = parseAttributes();
String uri = attrs.getValue("uri");
String prefix = attrs.getValue("prefix");
if (prefix != null) {
Mark prevMark = pageInfo.getNonCustomTagPrefix(prefix);
if (prevMark != null) {
err.jspError(reader.mark(), "jsp.error.prefix.use_before_dcl",
prefix, prevMark.getFile(), ""
+ prevMark.getLineNumber());
}
if (uri != null) {
String uriPrev = pageInfo.getURI(prefix);
if (uriPrev != null && !uriPrev.equals(uri)) {
err.jspError(reader.mark(), "jsp.error.prefix.refined",
prefix, uri, uriPrev);
}
if (pageInfo.getTaglib(uri) == null) {
TagLibraryInfoImpl impl = null;
if (ctxt.getOptions().isCaching()) {
impl = (TagLibraryInfoImpl) ctxt.getOptions()
.getCache().get(uri);
}
if (impl == null) {
String[] location = ctxt.getTldLocation(uri);
impl = new TagLibraryInfoImpl(ctxt, parserController, pageInfo,
prefix, uri, location, err);
if (ctxt.getOptions().isCaching()) {
ctxt.getOptions().getCache().put(uri, impl);
}
} else {
// Current compilation context needs location of cached
// tag files
for (TagFileInfo info : impl.getTagFiles()) {
ctxt.setTagFileJarUrl(info.getPath(),
ctxt.getTagFileJarUrl());
}
}
pageInfo.addTaglib(uri, impl);
}
pageInfo.addPrefixMapping(prefix, uri);
} else {
String tagdir = attrs.getValue("tagdir");
if (tagdir != null) {
String urnTagdir = URN_JSPTAGDIR + tagdir;
if (pageInfo.getTaglib(urnTagdir) == null) {
pageInfo.addTaglib(urnTagdir,
new ImplicitTagLibraryInfo(ctxt,
parserController, pageInfo, prefix, tagdir, err));
}
pageInfo.addPrefixMapping(prefix, urnTagdir);
}
}
}
new Node.TaglibDirective(attrs, start, parent);
}
/*
* Parses a directive with the following syntax: Directive ::= S? ( 'page'
* PageDirective | 'include' IncludeDirective | 'taglib' TagLibDirective) S?
* '%>'
*
* TagDirective ::= S? ('tag' PageDirective | 'include' IncludeDirective |
* 'taglib' TagLibDirective) | 'attribute AttributeDirective | 'variable
* VariableDirective S? '%>'
*/
private void parseDirective(Node parent) throws JasperException {
reader.skipSpaces();
String directive = null;
if (reader.matches("page")) {
directive = "<%@ page";
if (isTagFile) {
err.jspError(reader.mark(), "jsp.error.directive.istagfile",
directive);
}
parsePageDirective(parent);
} else if (reader.matches("include")) {
directive = "<%@ include";
parseIncludeDirective(parent);
} else if (reader.matches("taglib")) {
if (directivesOnly) {
// No need to get the tagLibInfo objects. This alos suppresses
// parsing of any tag files used in this tag file.
return;
}
directive = "<%@ taglib";
parseTaglibDirective(parent);
} else if (reader.matches("tag")) {
directive = "<%@ tag";
if (!isTagFile) {
err.jspError(reader.mark(), "jsp.error.directive.isnottagfile",
directive);
}
parseTagDirective(parent);
} else if (reader.matches("attribute")) {
directive = "<%@ attribute";
if (!isTagFile) {
err.jspError(reader.mark(), "jsp.error.directive.isnottagfile",
directive);
}
parseAttributeDirective(parent);
} else if (reader.matches("variable")) {
directive = "<%@ variable";
if (!isTagFile) {
err.jspError(reader.mark(), "jsp.error.directive.isnottagfile",
directive);
}
parseVariableDirective(parent);
} else {
err.jspError(reader.mark(), "jsp.error.invalid.directive");
}
reader.skipSpaces();
if (!reader.matches("%>")) {
err.jspError(start, "jsp.error.unterminated", directive);
}
}
/*
* Parses a directive with the following syntax:
*
* XMLJSPDirectiveBody ::= S? ( ( 'page' PageDirectiveAttrList S? ( '/>' | (
* '>' S? ETag ) ) | ( 'include' IncludeDirectiveAttrList S? ( '/>' | ( '>'
* S? ETag ) ) | <TRANSLATION_ERROR>
*
* XMLTagDefDirectiveBody ::= ( ( 'tag' TagDirectiveAttrList S? ( '/>' | (
* '>' S? ETag ) ) | ( 'include' IncludeDirectiveAttrList S? ( '/>' | ( '>'
* S? ETag ) ) | ( 'attribute' AttributeDirectiveAttrList S? ( '/>' | ( '>'
* S? ETag ) ) | ( 'variable' VariableDirectiveAttrList S? ( '/>' | ( '>' S?
* ETag ) ) ) | <TRANSLATION_ERROR>
*/
private void parseXMLDirective(Node parent) throws JasperException {
reader.skipSpaces();
String eTag = null;
if (reader.matches("page")) {
eTag = "jsp:directive.page";
if (isTagFile) {
err.jspError(reader.mark(), "jsp.error.directive.istagfile",
"<" + eTag);
}
parsePageDirective(parent);
} else if (reader.matches("include")) {
eTag = "jsp:directive.include";
parseIncludeDirective(parent);
} else if (reader.matches("tag")) {
eTag = "jsp:directive.tag";
if (!isTagFile) {
err.jspError(reader.mark(), "jsp.error.directive.isnottagfile",
"<" + eTag);
}
parseTagDirective(parent);
} else if (reader.matches("attribute")) {
eTag = "jsp:directive.attribute";
if (!isTagFile) {
err.jspError(reader.mark(), "jsp.error.directive.isnottagfile",
"<" + eTag);
}
parseAttributeDirective(parent);
} else if (reader.matches("variable")) {
eTag = "jsp:directive.variable";
if (!isTagFile) {
err.jspError(reader.mark(), "jsp.error.directive.isnottagfile",
"<" + eTag);
}
parseVariableDirective(parent);
} else {
err.jspError(reader.mark(), "jsp.error.invalid.directive");
}
reader.skipSpaces();
if (reader.matches(">")) {
reader.skipSpaces();
if (!reader.matchesETag(eTag)) {
err.jspError(start, "jsp.error.unterminated", "<" + eTag);
}
} else if (!reader.matches("/>")) {
err.jspError(start, "jsp.error.unterminated", "<" + eTag);
}
}
/*
* Parses a tag directive with the following syntax: PageDirective ::= ( S
* Attribute)*
*/
private void parseTagDirective(Node parent) throws JasperException {
Attributes attrs = parseAttributes();
Node.TagDirective n = new Node.TagDirective(attrs, start, parent);
/*
* A page directive may contain multiple 'import' attributes, each of
* which consists of a comma-separated list of package names. Store each
* list with the node, where it is parsed.
*/
for (int i = 0; i < attrs.getLength(); i++) {
if ("import".equals(attrs.getQName(i))) {
n.addImport(attrs.getValue(i));
}
}
}
/*
* Parses a attribute directive with the following syntax:
* AttributeDirective ::= ( S Attribute)*
*/
private void parseAttributeDirective(Node parent) throws JasperException {
Attributes attrs = parseAttributes();
Node.AttributeDirective n = new Node.AttributeDirective(attrs, start,
parent);
}
/*
* Parses a variable directive with the following syntax: PageDirective ::= (
* S Attribute)*
*/
private void parseVariableDirective(Node parent) throws JasperException {
Attributes attrs = parseAttributes();
Node.VariableDirective n = new Node.VariableDirective(attrs, start,
parent);
}
/*
* JSPCommentBody ::= (Char* - (Char* '--%>')) '--%>'
*/
private void parseComment(Node parent) throws JasperException {
start = reader.mark();
Mark stop = reader.skipUntil("--%>");
if (stop == null) {
err.jspError(start, "jsp.error.unterminated", "<%--");
}
new Node.Comment(reader.getText(start, stop), start, parent);
}
/*
* DeclarationBody ::= (Char* - (char* '%>')) '%>'
*/
private void parseDeclaration(Node parent) throws JasperException {
start = reader.mark();
Mark stop = reader.skipUntil("%>");
if (stop == null) {
err.jspError(start, "jsp.error.unterminated", "<%!");
}
new Node.Declaration(parseScriptText(reader.getText(start, stop)),
start, parent);
}
/*
* XMLDeclarationBody ::= ( S? '/>' ) | ( S? '>' (Char* - (char* '<'))
* CDSect?)* ETag | <TRANSLATION_ERROR> CDSect ::= CDStart CData CDEnd
* CDStart ::= '<![CDATA[' CData ::= (Char* - (Char* ']]>' Char*)) CDEnd
* ::= ']]>'
*/
private void parseXMLDeclaration(Node parent) throws JasperException {
reader.skipSpaces();
if (!reader.matches("/>")) {
if (!reader.matches(">")) {
err.jspError(start, "jsp.error.unterminated",
"<jsp:declaration>");
}
Mark stop;
String text;
while (true) {
start = reader.mark();
stop = reader.skipUntil("<");
if (stop == null) {
err.jspError(start, "jsp.error.unterminated",
"<jsp:declaration>");
}
text = parseScriptText(reader.getText(start, stop));
new Node.Declaration(text, start, parent);
if (reader.matches("![CDATA[")) {
start = reader.mark();
stop = reader.skipUntil("]]>");
if (stop == null) {
err.jspError(start, "jsp.error.unterminated", "CDATA");
}
text = parseScriptText(reader.getText(start, stop));
new Node.Declaration(text, start, parent);
} else {
break;
}
}
if (!reader.matchesETagWithoutLessThan("jsp:declaration")) {
err.jspError(start, "jsp.error.unterminated",
"<jsp:declaration>");
}
}
}
/*
* ExpressionBody ::= (Char* - (char* '%>')) '%>'
*/
private void parseExpression(Node parent) throws JasperException {
start = reader.mark();
Mark stop = reader.skipUntil("%>");
if (stop == null) {
err.jspError(start, "jsp.error.unterminated", "<%=");
}
new Node.Expression(parseScriptText(reader.getText(start, stop)),
start, parent);
}
/*
* XMLExpressionBody ::= ( S? '/>' ) | ( S? '>' (Char* - (char* '<'))
* CDSect?)* ETag ) | <TRANSLATION_ERROR>
*/
private void parseXMLExpression(Node parent) throws JasperException {
reader.skipSpaces();
if (!reader.matches("/>")) {
if (!reader.matches(">")) {
err.jspError(start, "jsp.error.unterminated",
"<jsp:expression>");
}
Mark stop;
String text;
while (true) {
start = reader.mark();
stop = reader.skipUntil("<");
if (stop == null) {
err.jspError(start, "jsp.error.unterminated",
"<jsp:expression>");
}
text = parseScriptText(reader.getText(start, stop));
new Node.Expression(text, start, parent);
if (reader.matches("![CDATA[")) {
start = reader.mark();
stop = reader.skipUntil("]]>");
if (stop == null) {
err.jspError(start, "jsp.error.unterminated", "CDATA");
}
text = parseScriptText(reader.getText(start, stop));
new Node.Expression(text, start, parent);
} else {
break;
}
}
if (!reader.matchesETagWithoutLessThan("jsp:expression")) {
err.jspError(start, "jsp.error.unterminated",
"<jsp:expression>");
}
}
}
/*
* ELExpressionBody (following "${" to first unquoted "}") // XXX add formal
* production and confirm implementation against it, // once it's decided
*/
private void parseELExpression(Node parent, char type) throws JasperException {
start = reader.mark();
Mark last = null;
boolean singleQuoted = false, doubleQuoted = false;
int currentChar;
do {
// XXX could move this logic to JspReader
last = reader.mark(); // XXX somewhat wasteful
currentChar = reader.nextChar();
if (currentChar == '\\' && (singleQuoted || doubleQuoted)) {
// skip character following '\' within quotes
reader.nextChar();
currentChar = reader.nextChar();
}
if (currentChar == -1)
err.jspError(start, "jsp.error.unterminated", type + "{");
if (currentChar == '"')
doubleQuoted = !doubleQuoted;
if (currentChar == '\'')
singleQuoted = !singleQuoted;
} while (currentChar != '}' || (singleQuoted || doubleQuoted));
new Node.ELExpression(type, reader.getText(start, last), start, parent);
}
/*
* ScriptletBody ::= (Char* - (char* '%>')) '%>'
*/
private void parseScriptlet(Node parent) throws JasperException {
start = reader.mark();
Mark stop = reader.skipUntil("%>");
if (stop == null) {
err.jspError(start, "jsp.error.unterminated", "<%");
}
new Node.Scriptlet(parseScriptText(reader.getText(start, stop)), start,
parent);
}
/*
* XMLScriptletBody ::= ( S? '/>' ) | ( S? '>' (Char* - (char* '<'))
* CDSect?)* ETag ) | <TRANSLATION_ERROR>
*/
private void parseXMLScriptlet(Node parent) throws JasperException {
reader.skipSpaces();
if (!reader.matches("/>")) {
if (!reader.matches(">")) {
err.jspError(start, "jsp.error.unterminated",
"<jsp:scriptlet>");
}
Mark stop;
String text;
while (true) {
start = reader.mark();
stop = reader.skipUntil("<");
if (stop == null) {
err.jspError(start, "jsp.error.unterminated",
"<jsp:scriptlet>");
}
text = parseScriptText(reader.getText(start, stop));
new Node.Scriptlet(text, start, parent);
if (reader.matches("![CDATA[")) {
start = reader.mark();
stop = reader.skipUntil("]]>");
if (stop == null) {
err.jspError(start, "jsp.error.unterminated", "CDATA");
}
text = parseScriptText(reader.getText(start, stop));
new Node.Scriptlet(text, start, parent);
} else {
break;
}
}
if (!reader.matchesETagWithoutLessThan("jsp:scriptlet")) {
err.jspError(start, "jsp.error.unterminated",
"<jsp:scriptlet>");
}
}
}
/**
* Param ::= '<jsp:param' S Attributes S? EmptyBody S?
*/
private void parseParam(Node parent) throws JasperException {
if (!reader.matches("<jsp:param")) {
err.jspError(reader.mark(), "jsp.error.paramexpected");
}
Attributes attrs = parseAttributes();
reader.skipSpaces();
Node paramActionNode = new Node.ParamAction(attrs, start, parent);
parseEmptyBody(paramActionNode, "jsp:param");
reader.skipSpaces();
}
/*
* For Include: StdActionContent ::= Attributes ParamBody
*
* ParamBody ::= EmptyBody | ( '>' S? ( '<jsp:attribute' NamedAttributes )? '
Other Tomcat examples (source code examples)Here is a short list of links related to this Tomcat Parser.java source code file: |
| ... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.