alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Groovy example source code file (MarkupBuilder.java)

This example Groovy source code file (MarkupBuilder.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Groovy tags/keywords

buildersupport, indentprinter, indentprinter, io, map, markupbuilder, markupbuilder, markupbuilderhelper, object, object, printwriter, qname, string, string, stringbuilder, util

The Groovy MarkupBuilder.java source code

/*
 * Copyright 2003-2011 the original author or authors.
 *
 * Licensed 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 groovy.xml;

import groovy.util.BuilderSupport;
import groovy.util.IndentPrinter;

import java.io.PrintWriter;
import java.io.Writer;
import java.util.Map;
import java.util.Iterator;

/**
 * <p>A helper class for creating XML or HTML markup.
 * The builder supports various 'pretty printed' formats.</p>
 * <p/>
 * <p>Example:

* <pre>new MarkupBuilder().root { * a( a1:'one' ) { * b { mkp.yield( '3 < 5' ) } * c( a2:'two', 'blah' ) * } * }</pre> * Will print the following to System.out: * <pre><root> * <a a1='one'> * <b>3 &lt; 5</b> * <c a2='two'>blah</c> * </a> * </root></pre> * Notes: * <ul> * <li>mkp is a special namespace used to escape * away from the normal building mode of the builder and get access * to helper markup methods such as 'yield' and 'yieldUnescaped'. * See the javadoc for {@link #getMkp()} for further details.</li> * <li>Note that tab, newline and carriage return characters are escaped within attributes, i.e. will become , and respectively * </ul> * @author <a href="mailto:james@coredevelopers.net">James Strachan * @author Stefan Matthias Aust * @author <a href="mailto:scottstirling@rcn.com">Scott Stirling * @author Paul King * @version $Revision: 22306 $ */ public class MarkupBuilder extends BuilderSupport { private IndentPrinter out; private boolean nospace; private int state; private boolean nodeIsEmpty = true; private boolean useDoubleQuotes = false; private boolean omitNullAttributes = false; private boolean omitEmptyAttributes = false; private boolean expandEmptyElements = false; /** * Prints markup to System.out * * @see IndentPrinter#IndentPrinter() */ public MarkupBuilder() { this(new IndentPrinter()); } /** * Sends markup to the given PrintWriter * * @param pw the PrintWriter to use * @see IndentPrinter#IndentPrinter(Writer) */ public MarkupBuilder(PrintWriter pw) { this(new IndentPrinter(pw)); } /** * Sends markup to the given Writer but first wrapping it in a PrintWriter * * @param writer the writer to use * @see IndentPrinter#IndentPrinter(Writer) */ public MarkupBuilder(Writer writer) { this(new IndentPrinter(new PrintWriter(writer))); } /** * Sends markup to the given IndentPrinter. Use this option if you want * to customize the indent used or provide your own IndentPrinter. * * @param out the IndentPrinter to use */ public MarkupBuilder(IndentPrinter out) { this.out = out; } /** * Returns <code>true if attribute values are output with * double quotes; <code>false if single quotes are used. * By default, single quotes are used. * * @return true if double quotes are used for attributes */ public boolean getDoubleQuotes() { return this.useDoubleQuotes; } /** * Sets whether the builder outputs attribute values in double * quotes or single quotes. * * @param useDoubleQuotes If this parameter is <code>true, * double quotes are used; otherwise, single quotes are. */ public void setDoubleQuotes(boolean useDoubleQuotes) { this.useDoubleQuotes = useDoubleQuotes; } /** * Determine whether null attributes will appear in the produced markup. * * @return <code>true, if null attributes will be * removed from the resulting markup. */ public boolean isOmitNullAttributes() { return omitNullAttributes; } /** * Allows null attributes to be removed from the generated markup. * * @param omitNullAttributes if <code>true, null * attributes will not be included in the resulting markup. * If <code>false null attributes will be included in the * markup as empty strings regardless of the omitEmptyAttribute * setting. Defaults to <code>false. */ public void setOmitNullAttributes(boolean omitNullAttributes) { this.omitNullAttributes = omitNullAttributes; } /** * Determine whether empty attributes will appear in the produced markup. * * @return <code>true, if empty attributes will be * removed from the resulting markup. */ public boolean isOmitEmptyAttributes() { return omitEmptyAttributes; } /** * Allows empty attributes to be removed from the generated markup. * * @param omitEmptyAttributes if <code>true, empty * attributes will not be included in the resulting markup. * Defaults to <code>false. */ public void setOmitEmptyAttributes(boolean omitEmptyAttributes) { this.omitEmptyAttributes = omitEmptyAttributes; } /** * Whether empty elements are expanded from <tagName/> to <tagName></tagName>. * * @return <code>true, if empty elements will be represented by an opening tag * followed immediately by a closing tag. */ public boolean isExpandEmptyElements() { return expandEmptyElements; } /** * Whether empty elements are expanded from <tagName/> to . * * @param expandEmptyElements if <code>true, empty * elements will be represented by an opening tag * followed immediately by a closing tag. * Defaults to <code>false. */ public void setExpandEmptyElements(boolean expandEmptyElements) { this.expandEmptyElements = expandEmptyElements; } protected IndentPrinter getPrinter() { return this.out; } protected void setParent(Object parent, Object child) { } /** * Property that may be called from within your builder closure to access * helper methods, namely {@link MarkupBuilderHelper#yield(String)}, * {@link MarkupBuilderHelper#yieldUnescaped(String)}, * {@link MarkupBuilderHelper#pi(Map)}, * {@link MarkupBuilderHelper#xmlDeclaration(Map)} and * {@link MarkupBuilderHelper#comment(String)}. * * @return this MarkupBuilder */ public Object getMkp() { return new MarkupBuilderHelper(this); } /** * Produce an XML processing instruction in the output. * For example: * <pre> * mkp.pi("xml-stylesheet":[href:"mystyle.css", type:"text/css"]) * </pre> * * @param args a map with a single entry whose key is the name of the * processing instruction and whose value is the attributes * for the processing instruction. */ void pi(Map<String, Map args) { Iterator<Map.Entry> iterator = args.entrySet().iterator(); if (iterator.hasNext()) { Map.Entry<String, Map mapEntry = iterator.next(); createNode("?" + mapEntry.getKey(), mapEntry.getValue()); state = 2; out.println("?>"); } } void yield(String value, boolean escaping) { if (state == 1) { state = 2; this.nodeIsEmpty = false; out.print(">"); } if (state == 2 || state == 3) { out.print(escaping ? escapeElementContent(value) : value); } } protected Object createNode(Object name) { Object theName = getName(name); toState(1, theName); this.nodeIsEmpty = true; return theName; } protected Object createNode(Object name, Object value) { Object theName = getName(name); if (value == null) { return createNode(theName); } else { toState(2, theName); this.nodeIsEmpty = false; out.print(">"); out.print(escapeElementContent(value.toString())); return theName; } } protected Object createNode(Object name, Map attributes, Object value) { Object theName = getName(name); toState(1, theName); for (Object p : attributes.entrySet()) { Map.Entry entry = (Map.Entry) p; Object attributeValue = entry.getValue(); boolean skipNull = attributeValue == null && omitNullAttributes; boolean skipEmpty = attributeValue != null && omitEmptyAttributes && attributeValue.toString().length() == 0; if (!skipNull && !skipEmpty) { out.print(" "); // Output the attribute name, print(entry.getKey().toString()); // Output the attribute value within quotes. Use whichever // type of quotes are currently configured. out.print(useDoubleQuotes ? "=\"" : "='"); print(attributeValue == null ? "" : escapeAttributeValue(attributeValue.toString())); out.print(useDoubleQuotes ? "\"" : "'"); } } if (value != null) { yield(value.toString(), true); } else { nodeIsEmpty = true; } return theName; } protected Object createNode(Object name, Map attributes) { return createNode(name, attributes, null); } protected void nodeCompleted(Object parent, Object node) { toState(3, node); out.flush(); } protected void print(Object node) { out.print(node == null ? "null" : node.toString()); } protected Object getName(String methodName) { return super.getName(methodName); } /** * Returns a String with special XML characters escaped as entities so that * output XML is valid. Escapes the following characters as corresponding * entities: * <ul> * <li>\' as &apos; * <li>& as &amp; * <li>< as &lt; * <li>> as &gt; * </ul> * * @param value to be searched and replaced for XML special characters. * @return value with XML characters escaped * @see #escapeXmlValue(String, boolean) * @deprecated */ protected String transformValue(String value) { // & has to be checked and replaced before others if (value.matches(".*&.*")) { value = value.replaceAll("&", "&"); } if (value.matches(".*\\'.*")) { value = value.replaceAll("\'", "'"); } if (value.matches(".*<.*")) { value = value.replaceAll("<", "<"); } if (value.matches(".*>.*")) { value = value.replaceAll(">", ">"); } return value; } /** * Escapes a string so that it can be used directly as an XML * attribute value. * * @param value The string to escape. * @return A new string in which all characters that require escaping * have been replaced with the corresponding XML entities. * @see #escapeXmlValue(String, boolean) */ private String escapeAttributeValue(String value) { return escapeXmlValue(value, true); } /** * Escapes a string so that it can be used directly in XML element * content. * * @param value The string to escape. * @return A new string in which all characters that require escaping * have been replaced with the corresponding XML entities. * @see #escapeXmlValue(String, boolean) */ private String escapeElementContent(String value) { return escapeXmlValue(value, false); } /** * Escapes a string so that it can be used in XML text successfully. * It replaces the following characters with the corresponding XML * entities: * <ul> * <li>& as &amp; * <li>< as &lt; * <li>> as &gt; * </ul> * If the string is to be added as an attribute value, these * characters are also escaped: * <ul> * <li>' as &apos; * </ul> * * @param value The string to escape. * @param isAttrValue <code>true if the string is to be used * as an attribute value, otherwise <code>false. * @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) { if (value == null) throw new IllegalArgumentException(); StringBuilder sb = null; // lazy create for edge-case efficiency for (int i = 0, len = value.length(); i < len; i++) { final char ch = value.charAt(i); final String replacement = checkForReplacement(isAttrValue, ch); if (replacement != null) { // output differs from input; we write to our local buffer if (sb == null) { sb = new StringBuilder((int) (1.1 * len)); sb.append(value.substring(0, i)); } sb.append(replacement); } else if (sb != null) { // earlier output differs from input; we write to our local buffer sb.append(ch); } } return sb == null ? value : sb.toString(); } private String checkForReplacement(boolean isAttrValue, char ch) { switch (ch) { case '&': return "&"; case '<': return "<"; case '>': return ">"; case '\n': if (isAttrValue) return " "; break; case '\r': if (isAttrValue) return " "; break; case '\t': if (isAttrValue) return " "; 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 && useDoubleQuotes) return """; break; case '\'': // The apostrophe is only escaped if the value is for an // attribute, as opposed to element content, and if the // builder is configured to surround attribute values with // single quotes. if (isAttrValue && !useDoubleQuotes) return "'"; break; } return null; } private void toState(int next, Object name) { switch (state) { case 0: switch (next) { case 1: case 2: out.print("<"); print(name); break; case 3: throw new Error(); } break; case 1: switch (next) { case 1: case 2: out.print(">"); if (nospace) { nospace = false; } else { out.println(); out.incrementIndent(); out.printIndent(); } out.print("<"); print(name); break; case 3: if (nodeIsEmpty) { if (expandEmptyElements) { out.print("></"); print(name); out.print(">"); } else { out.print(" />"); } } break; } break; case 2: switch (next) { case 1: case 2: if (!nodeIsEmpty) { out.println(); out.incrementIndent(); out.printIndent(); } out.print("<"); print(name); break; case 3: out.print("</"); print(name); out.print(">"); break; } break; case 3: switch (next) { case 1: case 2: if (nospace) { nospace = false; } else { out.println(); out.printIndent(); } out.print("<"); print(name); break; case 3: if (nospace) { nospace = false; } else { out.println(); out.decrementIndent(); out.printIndent(); } out.print("</"); print(name); out.print(">"); break; } break; } state = next; } private Object getName(Object name) { if (name instanceof QName) { return ((QName) name).getQualifiedName(); } return name; } }

Other Groovy examples (source code examples)

Here is a short list of links related to this Groovy MarkupBuilder.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 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.