/* * 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;
/** * An implementation of <code>jakarta.servlet.jsp.tagext.PageData</code> which * builds the XML view of a given page. * * The XML view is built in two passes: * * During the first pass, the FirstPassVisitor collects the attributes of the * top-level jsp:root and those of the jsp:root elements of any included * pages, and adds them to the jsp:root element of the XML view. * In addition, any taglib directives are converted into xmlns: attributes and * added to the jsp:root element of the XML view. * This pass ignores any nodes other than JspRoot and TaglibDirective. * * During the second pass, the SecondPassVisitor produces the XML view, using * the combined jsp:root attributes determined in the first pass and any * remaining pages nodes (this pass ignores any JspRoot and TaglibDirective * nodes). * * @author Jan Luehe
*/ class PageDataImpl extends PageData implements TagConstants {
// string buffer used to build XML view privatefinal StringBuilder buf;
/** * @param page the page nodes from which to generate the XML view * @param compiler The compiler for this page * * @throws JasperException If an error occurs
*/
PageDataImpl(Node.Nodes page, Compiler compiler) throws JasperException {
// First pass
FirstPassVisitor firstPass = new FirstPassVisitor(page.getRoot(),
compiler.getPageInfo());
page.visit(firstPass);
// Second pass
buf = new StringBuilder();
SecondPassVisitor secondPass
= new SecondPassVisitor(page.getRoot(), buf, compiler,
firstPass.getJspIdPrefix());
page.visit(secondPass);
}
/** * Returns the input stream of the XML view. * * @return the input stream of the XML view
*/
@Override public InputStream getInputStream() { returnnew ByteArrayInputStream(
buf.toString().getBytes(StandardCharsets.UTF_8));
}
/* * First-pass Visitor for JspRoot nodes (representing jsp:root elements) * and TablibDirective nodes, ignoring any other nodes. * * The purpose of this Visitor is to collect the attributes of the * top-level jsp:root and those of the jsp:root elements of any included * pages, and add them to the jsp:root element of the XML view. * In addition, this Visitor converts any taglib directives into xmlns: * attributes and adds them to the jsp:root element of the XML view.
*/ privatestaticclass FirstPassVisitor extends Node.Visitor implements TagConstants {
@Override publicvoid visit(Node.Root n) throws JasperException {
visitBody(n); if (n == root) { /* * Top-level page. * * Add * xmlns:jsp="http://java.sun.com/JSP/Page" * attribute only if not already present.
*/ if (!JSP_URI.equals(rootAttrs.getValue("xmlns:jsp"))) {
rootAttrs.addAttribute("", "", "xmlns:jsp", "CDATA",
JSP_URI);
}
if (pageInfo.isJspPrefixHijacked()) { /* * 'jsp' prefix has been hijacked, that is, bound to a * namespace other than the JSP namespace. This means that * when adding an 'id' attribute to each element, we can't * use the 'jsp' prefix. Therefore, create a new prefix * (one that is unique across the translation unit) for use * by the 'id' attribute, and bind it to the JSP namespace
*/
jspIdPrefix += "jsp"; while (pageInfo.containsPrefix(jspIdPrefix)) {
jspIdPrefix += "jsp";
}
rootAttrs.addAttribute("", "", "xmlns:" + jspIdPrefix, "CDATA", JSP_URI);
}
/* * Second-pass Visitor responsible for producing XML view and assigning * each element a unique jsp:id attribute.
*/ privatestaticclass SecondPassVisitor extends Node.Visitor implements TagConstants {
/* * Visits jsp:root element of JSP page in XML syntax. * * Any nested jsp:root elements (from pages included via an * include directive) are ignored.
*/
@Override publicvoid visit(Node.JspRoot n) throws JasperException {
visitBody(n);
}
@Override publicvoid visit(Node.TemplateText n) throws JasperException { /* * If the template text came from a JSP page written in JSP syntax, * create a jsp:text element for it (JSP 5.3.2).
*/
appendText(n.getText(), !n.getRoot().isXmlSyntax());
}
/* * Appends the given tag, including its body, to the XML view.
*/ privatevoid appendTag(Node n) throws JasperException {
appendTag(n, false);
}
/* * Appends the given tag, including its body, to the XML view, * and optionally reset default namespace to "", if none specified.
*/ privatevoid appendTag(Node n, boolean addDefaultNS) throws JasperException {
Node.Nodes body = n.getBody();
String text = n.getText();
if (ROOT_ACTION.equals(n.getLocalName()) || body != null
|| text != null) {
buf.append(">\n"); if (ROOT_ACTION.equals(n.getLocalName())) { if (compiler.getCompilationContext().isTagFile()) {
appendTagDirective();
} else {
appendPageDirective();
}
} if (body != null) {
body.visit(this);
} else {
appendText(text, false);
}
buf.append("" + n.getQName() + ">\n");
} else {
buf.append("/>\n");
}
}
/* * Appends the page directive with the given attributes to the XML * view. * * Since the import attribute of the page directive is the only page * attribute that is allowed to appear multiple times within the same * document, and since XML allows only single-value attributes, * the values of multiple import attributes must be combined into one, * separated by comma. * * If the given page directive contains just 'contentType' and/or * 'pageEncoding' attributes, we ignore it, as we've already appended * a page directive containing just these two attributes.
*/ privatevoid appendPageDirective(Node.PageDirective n) { boolean append = false;
Attributes attrs = n.getAttributes(); int len = (attrs == null) ? 0 : attrs.getLength(); for (int i=0; i<len; i++) {
@SuppressWarnings("null") // If attrs==null, len == 0
String attrName = attrs.getQName(i); if (!"pageEncoding".equals(attrName)
&& !"contentType".equals(attrName)) {
append = true; break;
}
} if (!append) { return;
}
// append remaining attributes for (int i=0; i<len; i++) {
@SuppressWarnings("null") // If attrs==null, len == 0
String attrName = attrs.getQName(i); if ("import".equals(attrName) || "contentType".equals(attrName)
|| "pageEncoding".equals(attrName)) { /* * Page directive's 'import' attribute is considered * further down, and its 'pageEncoding' and 'contentType' * attributes are ignored, since we've already appended * a new page directive containing just these two * attributes
*/ continue;
}
String value = attrs.getValue(i);
buf.append(" ").append(attrName).append("=\"");
buf.append(JspUtil.getExprInXml(value)).append("\"\n");
} if (n.getImports().size() > 0) { // Concatenate names of imported classes/packages boolean first = true; for (String i : n.getImports()) { if (first) {
first = false;
buf.append(" import=\"");
} else {
buf.append(',');
}
buf.append(JspUtil.getExprInXml(i));
}
buf.append("\"\n");
}
buf.append("/>\n");
}
/* * Appends a page directive with 'pageEncoding' and 'contentType' * attributes. * * The value of the 'pageEncoding' attribute is hard-coded * to UTF-8, whereas the value of the 'contentType' attribute, which * is identical to what the container will pass to * ServletResponse.setContentType(), is derived from the pageInfo.
*/ privatevoid appendPageDirective() {
buf.append('<').append(JSP_PAGE_DIRECTIVE_ACTION);
buf.append("\n");
/* * Appends the tag directive with the given attributes to the XML * view. * * If the given tag directive contains just a 'pageEncoding' * attributes, we ignore it, as we've already appended * a tag directive containing just this attributes.
*/ privatevoid appendTagDirective(Node.TagDirective n) throws JasperException {
boolean append = false;
Attributes attrs = n.getAttributes(); int len = (attrs == null) ? 0 : attrs.getLength(); for (int i=0; i<len; i++) {
@SuppressWarnings("null") // If attrs==null, len == 0
String attrName = attrs.getQName(i); if (!"pageEncoding".equals(attrName)) {
append = true; break;
}
} if (!append) { return;
}
appendTag(n);
}
/* * Appends a tag directive containing a single 'pageEncoding' * attribute whose value is hard-coded to UTF-8.
*/ privatevoid appendTagDirective() {
buf.append('<').append(JSP_TAG_DIRECTIVE_ACTION);
buf.append("\n");
/* * Appends the given text as a CDATA section to the XML view, unless * the text has already been marked as CDATA.
*/ privatevoid appendCDATA(String text) {
buf.append(CDATA_START_SECTION);
buf.append(escapeCDATA(text));
buf.append(CDATA_END_SECTION);
}
/* * Escapes any occurrences of "]]>" (by replacing them with "]]>") * within the given text, so it can be included in a CDATA section.
*/ private String escapeCDATA(String text) { if( text==null ) { return"";
} int len = text.length();
CharArrayWriter result = new CharArrayWriter(len); for (int i=0; i<len; i++) { if (((i+2) < len)
&& (text.charAt(i) == ']')
&& (text.charAt(i+1) == ']')
&& (text.charAt(i+2) == '>')) { // match found
result.write(']');
result.write(']');
result.write('&');
result.write('g');
result.write('t');
result.write(';');
i += 2;
} else {
result.write(text.charAt(i));
}
} return result.toString();
}
/* * Appends the attributes of the given Node to the XML view.
*/ privatevoid printAttributes(Node n, boolean addDefaultNS) {
/* * Append "xmlns" attributes that represent tag libraries
*/
Attributes attrs = n.getTaglibAttributes(); int len = (attrs == null) ? 0 : attrs.getLength(); for (int i=0; i<len; i++) {
@SuppressWarnings("null") // If attrs==null, len == 0
String name = attrs.getQName(i);
String value = attrs.getValue(i);
buf.append(" ").append(name).append("=\"").append(value).append("\"\n");
}
/* * Append "xmlns" attributes that do not represent tag libraries
*/
attrs = n.getNonTaglibXmlnsAttributes();
len = (attrs == null) ? 0 : attrs.getLength(); boolean defaultNSSeen = false; for (int i=0; i<len; i++) {
@SuppressWarnings("null") // If attrs==null, len == 0
String name = attrs.getQName(i);
String value = attrs.getValue(i);
buf.append(" ").append(name).append("=\"").append(value).append("\"\n");
defaultNSSeen |= "xmlns".equals(name);
} if (addDefaultNS && !defaultNSSeen) {
buf.append(" xmlns=\"\"\n");
}
resetDefaultNS = false;
/* * Append all other attributes
*/
attrs = n.getAttributes();
len = (attrs == null) ? 0 : attrs.getLength(); for (int i=0; i<len; i++) {
@SuppressWarnings("null") // If attrs==null, len == 0
String name = attrs.getQName(i);
String value = attrs.getValue(i);
buf.append(" ").append(name).append("=\"");
buf.append(JspUtil.getExprInXml(value)).append("\"\n");
}
}
/* * Appends XML prolog with encoding declaration.
*/ privatevoid appendXmlProlog() {
buf.append("1.0\" encoding=\"UTF-8\" ?>\n");
}
}
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.20 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.