Index: src/main/groovy/xml/MarkupBuilder.java =================================================================== --- src/main/groovy/xml/MarkupBuilder.java (revision 17899) +++ src/main/groovy/xml/MarkupBuilder.java Fri Oct 09 21:29:24 EST 2009 @@ -21,10 +21,13 @@ import java.io.PrintWriter; import java.io.Writer; import java.util.Map; +import java.util.HashMap; +import java.util.Set; +import java.util.Iterator; /** - *

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

+ *

A helper class for creating XML or HTML markup. + * The builder supports various 'pretty printed' formats.

*

*

Example:

*
new MarkupBuilder().root {
@@ -174,56 +177,40 @@
 
     /**
      * Property that may be called from within your builder closure to access
-     * helper methods, namely {@link #yield(String)} and
-     * {@link #yieldUnescaped(String)}.
+     * 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 this;
+        return new MarkupBuilderHelper(this);
     }
 
     /**
-     * Prints data in the body of the current tag, escaping XML entities.
-     * For example: mkp.yield('5 < 7')
+     * Produce an XML processing instruction in the output.
+     * For example:
+     * 
+     * mkp.pi("xml-stylesheet":[href:"mystyle.css", type:"text/css"])
+     * 
* - * @param value an Object whose toString() representation is to be printed + * @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. */ - public void yield(Object value) { - yield(value.toString()); + void pi(Map> args) { + Iterator>> iterator = args.entrySet().iterator(); + if (iterator.hasNext()) { + Map.Entry> mapEntry = iterator.next(); + createNode("?" + mapEntry.getKey(), mapEntry.getValue()); + state = 2; + out.println("?>"); - } + } - - /** - * Prints data in the body of the current tag, escaping XML entities. - * For example: mkp.yield('5 < 7') - * - * @param value text to print - */ - public void yield(String value) { - yield(value, true); } - /** - * Print data in the body of the current tag. Does not escape XML entities. - * For example: mkp.yieldUnescaped('I am <i>happy</i>!'). - * - * @param value an Object whose toString() representation is to be printed - */ - public void yieldUnescaped(Object value) { - yieldUnescaped(value.toString()); - } - - /** - * Print data in the body of the current tag. Does not escape XML entities. - * For example: mkp.yieldUnescaped('I am <i>happy</i>!'). - * - * @param value the text or markup to print. - */ - public void yieldUnescaped(String value) { - yield(value, false); - } - - private void yield(String value, boolean escaping) { + void yield(String value, boolean escaping) { if (state == 1) { state = 2; this.nodeIsEmpty = false; @@ -275,7 +262,7 @@ } } if (value != null) { - yield(value.toString()); + yield(value.toString(), true); } else { nodeIsEmpty = true; } Index: src/main/groovy/xml/MarkupBuilderHelper.java =================================================================== --- src/main/groovy/xml/MarkupBuilderHelper.java Fri Oct 09 21:29:24 EST 2009 +++ src/main/groovy/xml/MarkupBuilderHelper.java Fri Oct 09 21:29:24 EST 2009 @@ -0,0 +1,139 @@ +/* + * Copyright 2003-2009 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 java.util.HashMap; +import java.util.Map; + +/** + * A helper class for MarkupBuilder. + * + * @author Paul King + */ +public class MarkupBuilderHelper { + private MarkupBuilder builder; + + /** + * @param builder the builder to delegate to + */ + public MarkupBuilderHelper(MarkupBuilder builder) { + this.builder = builder; + } + + /** + * Prints data in the body of the current tag, escaping XML entities. + * For example: mkp.yield('5 < 7') + * + * @param value an Object whose toString() representation is to be printed + */ + public void yield(Object value) { + yield(value.toString()); + } + + /** + * Prints data in the body of the current tag, escaping XML entities. + * For example: mkp.yield('5 < 7') + * + * @param value text to print + */ + public void yield(String value) { + builder.yield(value, true); + } + + /** + * Print data in the body of the current tag. Does not escape XML entities. + * For example: mkp.yieldUnescaped('I am <i>happy</i>!'). + * + * @param value an Object whose toString() representation is to be printed + */ + public void yieldUnescaped(Object value) { + yieldUnescaped(value.toString()); + } + + /** + * Print data in the body of the current tag. Does not escape XML entities. + * For example: mkp.yieldUnescaped('I am <i>happy</i>!'). + * + * @param value the text or markup to print. + */ + public void yieldUnescaped(String value) { + builder.yield(value, false); + } + + /** + * Produce a comment in the output. + *

+ * mkp.comment 'string' is equivalent to + * mkp.yieldUnescaped '<!-- string -->'. + * To create an element with the name 'comment', you need + * to supply empty attributes, e.g.: + *

+     * comment('hello1')
+     * 
+ * or + *
+     * mkp.comment('hello1')
+     * 
+ * will produce: + *
+     * <!-- hello1 -->
+     * 
+ * while: + *
+     * comment('hello2', [:])
+     * 
+ * will produce: + *
+     * <comment>hello2</comment>
+     * 
+ * + * @param value the text within the comment. + */ + public void comment(String value) { + yieldUnescaped(""); + } + + /** + * Produce an XML declaration in the output. + * For example: + *
+     * mkp.xmlDeclaration(version:'1.0')
+     * 
+ * + * @param args the attributes for the declaration + */ + public void xmlDeclaration(Map args) { + Map> map = new HashMap>(); + map.put("xml", args); + pi(map); + } + + /** + * Produce an XML processing instruction in the output. + * For example: + *
+     * mkp.pi("xml-stylesheet":[href:"mystyle.css", type:"text/css"])
+     * 
+ * + * @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. + */ + public void pi(Map> args) { + builder.pi(args); + } + +} \ No newline at end of file Index: src/test/groovy/xml/MarkupBuilderTest.groovy =================================================================== --- src/test/groovy/xml/MarkupBuilderTest.groovy (revision 17903) +++ src/test/groovy/xml/MarkupBuilderTest.groovy Fri Oct 09 21:33:41 EST 2009 @@ -37,20 +37,6 @@ checkXml expectedXml, writer } - void testSmallTree() { - xml.root1(a:5, b:7) { - elem1('hello1') - elem2('hello2') - elem3(x:7) - } - assertExpectedXml '''\ - - hello1 - hello2 - -''' - } - /** * It is not recommended practice to use the value attribute * when also using nested content as there is no way to specify @@ -246,18 +232,6 @@ assert writer.toString() == "foo" } - void testMarkupBuilderAllowsMkpToBeDropped() { - def m = { - p { - yield 'Red: Hearts & Diamonds' - br() - yieldUnescaped 'Black: Spades & Clubs' - } - } - assertExpectedXml m, '''\ -

Red: Hearts & Diamonds\n
Black: Spades & Clubs \n

''' - } - private myMethod(x) { x.value='call to outside' return x Index: src/test/groovy/xml/StreamingMarkupBuilderTest.groovy =================================================================== --- src/test/groovy/xml/StreamingMarkupBuilderTest.groovy (revision 17903) +++ src/test/groovy/xml/StreamingMarkupBuilderTest.groovy Wed Oct 07 21:25:26 EST 2009 @@ -32,29 +32,4 @@ checkXml(expectedXml, writer) } - /** - * test some StreamingMarkupBuilder specific mkp functionality - */ - void testSmallTree() { - def m = { - mkp.xmlDeclaration(version:'1.0') - mkp.pi("xml-stylesheet":[href:"mystyle.css", type:"text/css"]) - root1(a:5, b:7) { - elem1('hello1') - elem2('hello2') - mkp.comment('hello3') - elem3(x:7) - } +} \ No newline at end of file - } - assertExpectedXml m, '''\ - - - - hello1 - hello2 - - -''' - } - -} \ No newline at end of file Index: src/test/groovy/xml/BuilderTestSupport.groovy =================================================================== --- src/test/groovy/xml/BuilderTestSupport.groovy (revision 17903) +++ src/test/groovy/xml/BuilderTestSupport.groovy Fri Oct 09 21:12:01 EST 2009 @@ -32,7 +32,7 @@ protected checkXml(String expectedXml, StringWriter writer) { XMLUnit.ignoreWhitespace = true def xmlDiff = new Diff(expectedXml, writer.toString()) - assert xmlDiff.similar(), xmlDiff.toString() + assert xmlDiff.similar(), xmlDiff.toString() + "\n" + writer.toString() } void testHref() { @@ -197,13 +197,44 @@ * yield and yieldUnescaped should call toString() if a non-String object is passed as argument */ void testYieldObjectToStringRepresentation() { - def out = new StringWriter() - new MarkupBuilder(out).table { + def m = { + table { - td(id: 999) { mkp.yield 999 } - td(id: 99) { mkp.yieldUnescaped 99 } - } + td(id: 999) { mkp.yield 999 } + td(id: 99) { mkp.yieldUnescaped 99 } + } + } + assertExpectedXml m, "
99999
" + } - assert !out.toString().contains('yield') + /** + * test special builder mkp functionality + */ + void testSmallTreeWithMkpFunctionality() { + def m = { + mkp.xmlDeclaration(version: '1.0') + mkp.pi("xml-stylesheet": [href: "mystyle.css", type: "text/css"]) + root1(a: 5, b: 7) { + elem1('hello1') + elem2('hello2') + mkp.comment('hello3') + comment('hello4', [:]) + comment(value: 'hello5') + comment {} + elem3(x: 7) - } + } + } + assertExpectedXml m, '''\ + + + + hello1 + hello2 + + hello4 + + + +''' + } } \ No newline at end of file