You are viewing a plain text version of this content. The canonical link for it is here.
Posted to taglibs-dev@jakarta.apache.org by ho...@apache.org on 2004/06/11 03:47:43 UTC
cvs commit: jakarta-taglibs/standard/src/org/apache/taglibs/standard/tag/common/core OutSupport.java Util.java
horwat 2004/06/10 18:47:43
Modified: standard/src/org/apache/taglibs/standard/functions
Functions.java
standard/src/org/apache/taglibs/standard/tag/common/core
OutSupport.java Util.java
Log:
Bugzilla #25382
Optimization of the xml escaping used by JSTL Functions and the out tag handlers
.
The new implementation in Functions is about 5x faster than the previous version
s. Data gathered using Mike Skells' test pages available in the Bugzilla bug #25
382 entry.
The escaping xml implementation in Util can be made generic for both Functions a
nd the out tag handler. Load tested the new Functions implementation with the ou
t tag handler and found it to be about 1.5x slower for text with many characters
that need to be escaped than a customized implementation that writes to the Jsp
Writer directly. Given the performance difference, went with a customized imple
mentation for the out tag handler.
Contributed by:
Mike Skells
Martin van Dijken
David Wall
Kris Schneider
Revision Changes Path
1.8 +2 -2 jakarta-taglibs/standard/src/org/apache/taglibs/standard/functions/Functions.java
Index: Functions.java
===================================================================
RCS file: /home/cvs/jakarta-taglibs/standard/src/org/apache/taglibs/standard/functions/Functions.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- Functions.java 28 Feb 2004 01:01:42 -0000 1.7
+++ Functions.java 11 Jun 2004 01:47:42 -0000 1.8
@@ -130,9 +130,9 @@
// Character replacement
public static String escapeXml(String input) {
- if (input == null) input = "";
+ if (input == null) return "";
return Util.escapeXml(input);
- }
+ }
public static String trim(String input) {
if (input == null) return "";
1.14 +36 -24 jakarta-taglibs/standard/src/org/apache/taglibs/standard/tag/common/core/OutSupport.java
Index: OutSupport.java
===================================================================
RCS file: /home/cvs/jakarta-taglibs/standard/src/org/apache/taglibs/standard/tag/common/core/OutSupport.java,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- OutSupport.java 28 Feb 2004 01:01:44 -0000 1.13
+++ OutSupport.java 11 Jun 2004 01:47:43 -0000 1.14
@@ -154,39 +154,51 @@
w.write(buf, 0, count);
}
} else {
- w.print(obj.toString());
+ w.write(obj.toString());
}
} else {
// escape XML chars
if (obj instanceof Reader) {
Reader reader = (Reader)obj;
- int c;
- while ((c=reader.read()) != -1) {
- escapeChar((char)c, w);
- }
+ char[] buf = new char[4096];
+ int count;
+ while ((count = reader.read(buf, 0, 4096)) != -1) {
+ writeEscapedXml(buf, count, w);
+ }
} else {
String text = obj.toString();
- // avoid needless double-buffering (is this really more efficient?)
- for (int i = 0; i < text.length(); i++) {
- char c = text.charAt(i);
- escapeChar(c, w);
- }
+ writeEscapedXml(text.toCharArray(), text.length(), w);
}
}
}
-
- private static void escapeChar(char c, JspWriter w) throws IOException {
- if (c == '&')
- w.print("&");
- else if (c == '<')
- w.print("<");
- else if (c == '>')
- w.print(">");
- else if (c == '"')
- w.print(""");
- else if (c == '\'')
- w.print("'");
- else
- w.print(c);
+
+ /**
+ *
+ * Optimized to create no extra objects and write directly
+ * to the JspWriter using blocks of escaped and unescaped characters
+ *
+ */
+ private static void writeEscapedXml(char[] buffer, int length, JspWriter w) throws IOException{
+ int start = 0;
+
+ for (int i = 0; i < length; i++) {
+ char c = buffer[i];
+ if (c <= Util.HIGHEST_SPECIAL) {
+ char[] escaped = Util.specialCharactersRepresentation[c];
+ if (escaped != null) {
+ // add unescaped portion
+ if (start < i) {
+ w.write(buffer,start,i-start);
+ }
+ // add escaped xml
+ w.write(escaped);
+ start = i + 1;
+ }
+ }
+ }
+ // add rest of unescaped portion
+ if (start < length) {
+ w.write(buffer,start,length-start);
+ }
}
}
1.15 +49 -21 jakarta-taglibs/standard/src/org/apache/taglibs/standard/tag/common/core/Util.java
Index: Util.java
===================================================================
RCS file: /home/cvs/jakarta-taglibs/standard/src/org/apache/taglibs/standard/tag/common/core/Util.java,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -r1.14 -r1.15
--- Util.java 28 Feb 2004 01:01:44 -0000 1.14
+++ Util.java 11 Jun 2004 01:47:43 -0000 1.15
@@ -44,6 +44,16 @@
private static final String LONG = "long";
private static final String FULL = "full";
+ public static final int HIGHEST_SPECIAL = '>';
+ public static char[][] specialCharactersRepresentation = new char[HIGHEST_SPECIAL + 1][];
+ static {
+ specialCharactersRepresentation['&'] = "&".toCharArray();
+ specialCharactersRepresentation['<'] = "<".toCharArray();
+ specialCharactersRepresentation['>'] = ">".toCharArray();
+ specialCharactersRepresentation['"'] = """.toCharArray();
+ specialCharactersRepresentation['\''] = "'".toCharArray();
+ }
+
/*
* Converts the given string description of a scope to the corresponding
* PageContext constant.
@@ -102,8 +112,10 @@
return ret;
}
+
+
/**
- * Performs the following substring replacements
+ * Performs the following substring replacements
* (to facilitate output to XML/HTML pages):
*
* & -> &
@@ -112,28 +124,44 @@
* " -> "
* ' -> '
*
- * See also OutSupport.out().
+ * See also OutSupport.writeEscapedXml().
*/
- public static String escapeXml(String input) {
- StringBuffer sb = new StringBuffer();
- for (int i = 0; i < input.length(); i++) {
- char c = input.charAt(i);
- if (c == '&')
- sb.append("&");
- else if (c == '<')
- sb.append("<");
- else if (c == '>')
- sb.append(">");
- else if (c == '"')
- sb.append(""");
- else if (c == '\'')
- sb.append("'");
- else
- sb.append(c);
+ public static String escapeXml(String buffer) {
+ int start = 0;
+ int length = buffer.length();
+ char[] arrayBuffer = buffer.toCharArray();
+ StringBuffer escapedBuffer = null;
+
+ for (int i = 0; i < length; i++) {
+ char c = arrayBuffer[i];
+ if (c <= HIGHEST_SPECIAL) {
+ char[] escaped = specialCharactersRepresentation[c];
+ if (escaped != null) {
+ // create StringBuffer to hold escaped xml string
+ if (start == 0) {
+ escapedBuffer = new StringBuffer(length + 5);
+ }
+ // add unescaped portion
+ if (start < i) {
+ escapedBuffer.append(arrayBuffer,start,i-start);
+ }
+ start = i + 1;
+ // add escaped xml
+ escapedBuffer.append(escaped);
+ }
+ }
}
- return sb.toString();
- }
-
+ // no xml escaping was necessary
+ if (start == 0) {
+ return buffer;
+ }
+ // add rest of unescaped portion
+ if (start < length) {
+ escapedBuffer.append(arrayBuffer,start,length-start);
+ }
+ return escapedBuffer.toString();
+ }
+
/**
* Get the value associated with a content-type attribute.
* Syntax defined in RFC 2045, section 5.1.
---------------------------------------------------------------------
To unsubscribe, e-mail: taglibs-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: taglibs-dev-help@jakarta.apache.org