### Eclipse Workspace Patch 1.0 #P groovy-core Index: src/main/groovy/xml/MarkupBuilder.java =================================================================== --- src/main/groovy/xml/MarkupBuilder.java (revision 14839) +++ src/main/groovy/xml/MarkupBuilder.java (working copy) @@ -26,7 +26,7 @@ /** *

A helper class for creating XML or HTML markup. This implementation outputs * markup in a 'pretty printed' format.

- * + * *

Example:

*
new MarkupBuilder().root {
  *   a( a1:'one' ) {
@@ -34,13 +34,13 @@
  *     c( a2:'two', 'blah' )
  *   }
  * }
- * Will print the following to System.out: + * Will print the following to System.out: *
<root>
  *   <a a1='one'>
  *     <b>3 &lt; 5</b>
  *     <c a2='two'>blah</c>
  *   </a>
- * </root>
+ * </root> * * @author James Strachan * @author Stefan Matthias Aust @@ -66,7 +66,7 @@ } /** - * Sends markup to the given PrintWriter + * Sends markup to the given PrintWriter * @see IndentPrinter#IndentPrinter(PrintWriter) */ public MarkupBuilder(PrintWriter writer) { @@ -74,7 +74,7 @@ } /** - * Sends markup to the given PrintWriter + * Sends markup to the given PrintWriter * @see IndentPrinter#IndentPrinter(PrintWriter) */ public MarkupBuilder(Writer writer) { @@ -83,7 +83,7 @@ /** * Sends markup to the given IndentPrinter. Use this option if you want - * to customize the indent used. + * to customize the indent used. */ public MarkupBuilder(IndentPrinter out) { this.out = out; @@ -160,8 +160,8 @@ protected void setParent(Object parent, Object child) { } /** - * Property that may be called from within your builder closure to access - * helper methods, namely {@link #yield(String)} and + * Property that may be called from within your builder closure to access + * helper methods, namely {@link #yield(String)} and * {@link #yieldUnescaped(String)}. * @return this MarkupBuilder */ @@ -306,7 +306,7 @@ * @see #escapeXmlValue(String, boolean) */ private String escapeAttributeValue(String value) { - return escapeXmlValue(value, true); + return escapeXmlValue(value, true, useDoubleQuotes); } /** @@ -318,7 +318,7 @@ * @see #escapeXmlValue(String, boolean) */ private String escapeElementContent(String value) { - return escapeXmlValue(value, false); + return escapeXmlValue(value, false, useDoubleQuotes); } /** @@ -337,57 +337,47 @@ * * @param value The string to escape. * @param isAttrValue true if the string is to be used - * as an attribute value, otherwise false. + * as an attribute value, otherwise false. + * @param useDoubleQuotes true if double quotes are used + * as attribute delimiter, or false otherwise. * @return A new string in which all characters that require escaping * have been replaced with the corresponding XML entities. */ - private String escapeXmlValue(String value, boolean isAttrValue) { - StringBuffer buffer = new StringBuffer(value); - for (int i = 0, n = buffer.length(); i < n; i++) { - switch (buffer.charAt(i)) { + private static String escapeXmlValue(String value, + boolean isAttrValue, + boolean useDoubleQuotes) + { + if (value == null) + throw new IllegalArgumentException(); + + StringBuffer buffer = null; + + for (int i = 0, len = value.length(); i < len; i++) { + final char ch = value.charAt(i); + final String replacement; + + switch (ch) + { case '&': - buffer.replace(i, i + 1, "&"); - - // We're replacing a single character by a string of - // length 5, so we need to update the index variable - // and the total length. - i += 4; - n += 4; + replacement = "&"; break; case '<': - buffer.replace(i, i + 1, "<"); - - // We're replacing a single character by a string of - // length 4, so we need to update the index variable - // and the total length. - i += 3; - n += 3; + replacement = "<"; break; case '>': - buffer.replace(i, i + 1, ">"); - - // We're replacing a single character by a string of - // length 4, so we need to update the index variable - // and the total length. - i += 3; - n += 3; + replacement = ">"; break; case '"': // The double quote is only escaped if the value is for // an attribute and the builder is configured to output // attribute values inside double quotes. - if (isAttrValue && this.useDoubleQuotes) { - buffer.replace(i, i + 1, """); - - // We're replacing a single character by a string of - // length 6, so we need to update the index variable - // and the total length. - i += 5; - n += 5; - } + if (isAttrValue && useDoubleQuotes) + replacement = """; + else + replacement = null; break; case '\'': @@ -395,25 +385,37 @@ // attribute, as opposed to element content, and if the // builder is configured to surround attribute values with // single quotes. - if (isAttrValue && !this.useDoubleQuotes){ - buffer.replace(i, i + 1, "'"); - - // We're replacing a single character by a string of - // length 6, so we need to update the index variable - // and the total length. - i += 5; - n += 5; - } + if (isAttrValue && !useDoubleQuotes) + replacement = "'"; + else + replacement = null; break; default: + replacement = null; break; } + + if (replacement != null) { + // output differs from input; we write to our local buffer + if (buffer == null) { + buffer = new StringBuffer((int)(1.1 * len)); + buffer.append(value.substring(0, i)); + } + + buffer.append(replacement); + } else if (buffer != null) { + // output differs from input; we write to our local buffer + buffer.append(ch); + } else { + // nothing to do + } } - return buffer.toString(); + return buffer == null ? value : buffer.toString(); } + private void toState(int next, Object name) { switch (state) { case 0: @@ -456,7 +458,7 @@ if (!nodeIsEmpty) { out.println(); out.incrementIndent(); - out.printIndent(); + out.printIndent(); } out.print("<"); print(name);