Author: johnh
Date: Mon Aug 18 19:27:54 2008
New Revision: 686935
URL: http://svn.apache.org/viewvc?rev=686935&view=rev
Log:
Adding ability for GadgetHtmlNode to render itself as HTML via
GadgetHtmlNode.render(Writer w).
Modified:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlNode.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/GadgetHtmlNodeTest.java
Modified:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlNode.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlNode.java?rev=686935&r1=686934&r2=686935&view=diff
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlNode.java
(original)
+++
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlNode.java
Mon Aug 18 19:27:54 2008
@@ -17,6 +17,8 @@
*/
package org.apache.shindig.gadgets.parse;
+import java.io.IOException;
+import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -25,6 +27,8 @@
import java.util.Map;
import java.util.Set;
+import org.apache.commons.lang.StringEscapeUtils;
+
/**
* Mutable wrapper around a [EMAIL PROTECTED] ParsedHtmlNode}.
* Used by rewriting to manipulate a parsed gadget DOM, and
@@ -280,6 +284,44 @@
this.text = text;
}
+ /**
+ * Render self as HTML. Rendering is relatively simple as no
+ * additional validation is performed on content beyond what
+ * the rest of the class provides, such as attribute key
+ * validation. All whitespace and comments are maintained. Nodes
+ * with zero children are rendered short-form (<foo/>)
+ * unless tagName is "style" since many browsers dislike short-form for that.
+ * One space is provided between attributes. Attribute values are surrounded
+ * in double-quotes. Null-valued attributes are rendered without ="value".
+ * Attributes are rendered in no particular order.
+ * @param w Writer to which to send content
+ * @throws IOException If the writer throws an error on append(...)
+ */
+ public void render(Writer w) throws IOException {
+ if (isText()) {
+ w.append(StringEscapeUtils.escapeHtml(getText()));
+ } else {
+ w.append('<').append(tagName);
+ for (String attrKey : getAttributeKeys()) {
+ String attrValue = getAttributeValue(attrKey);
+ w.append(' ').append(attrKey);
+ if (attrValue != null) {
+
w.append("=\"").append(StringEscapeUtils.escapeHtml(attrValue)).append('"');
+ }
+ }
+ if (children.size() == 0 &&
+ !tagName.equalsIgnoreCase("style")) {
+ w.append("/>");
+ } else {
+ w.append('>');
+ for (GadgetHtmlNode child : children) {
+ child.render(w);
+ }
+ w.append("</").append(tagName).append('>');
+ }
+ }
+ }
+
// Helper that cleans up and validates an attribute key
private String validateAttributeKey(String key) {
if (key == null) {
Modified:
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/GadgetHtmlNodeTest.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/GadgetHtmlNodeTest.java?rev=686935&r1=686934&r2=686935&view=diff
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/GadgetHtmlNodeTest.java
(original)
+++
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/GadgetHtmlNodeTest.java
Mon Aug 18 19:27:54 2008
@@ -24,6 +24,8 @@
import junit.framework.TestCase;
+import java.io.IOException;
+import java.io.StringWriter;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
@@ -431,4 +433,78 @@
// Expected condition
}
}
+
+ public void testRenderOnlyTextNode() {
+ String content = " hello, world!\n ";
+ assertEquals(content, renderNode(new GadgetHtmlNode(content)));
+ }
+
+ public void testRenderOnlyTagNodeShortForm() {
+ String[][] attribs = { { "id", "foo" }, { "bar", "baz" } };
+ GadgetHtmlNode tag = new GadgetHtmlNode("div", attribs);
+ assertEquals("<div bar=\"baz\" id=\"foo\"/>", renderNode(tag));
+ }
+
+ public void testRenderStyleSrcTag() {
+ String[][] attribs = { { "src", "http://www.foo.com/bar.css" } };
+ GadgetHtmlNode styleTag = new GadgetHtmlNode("style", attribs);
+ assertEquals("<style src=\"http://www.foo.com/bar.css\"></style>",
+ renderNode(styleTag));
+ }
+
+ public void testRenderEscapedAttribute() {
+ String[][] attribs = { { "foo", "<script&\"data\">" } };
+ GadgetHtmlNode escapedTag = new GadgetHtmlNode("div", attribs);
+ assertEquals("<div foo=\"<script&"data">\"/>",
+ renderNode(escapedTag));
+ }
+
+ public void testRenderNullValuedAttribute() {
+ String[][] attribs = { { "marker", null } };
+ GadgetHtmlNode tag = new GadgetHtmlNode("span", attribs);
+ assertEquals("<span marker/>", renderNode(tag));
+ }
+
+ public void testRenderEscapedTextContent() {
+ GadgetHtmlNode escapedTextNode = new GadgetHtmlNode("<script&\"data'>");
+ assertEquals("<script&"data'>",
+ renderNode(escapedTextNode));
+ }
+
+ public void testRenderAdjacentStringsInTag() {
+ GadgetHtmlNode container = new GadgetHtmlNode("div", null);
+ container.appendChild(new GadgetHtmlNode("one"));
+ container.appendChild(new GadgetHtmlNode("\n"));
+ container.appendChild(new GadgetHtmlNode(" two "));
+ assertEquals("<div>one\n two </div>", renderNode(container));
+ }
+
+ public void testRenderMixedContent() {
+ // Something of a catch-all for smaller above tests.
+ String[][] attribs = { { "readonly", null } };
+ GadgetHtmlNode parent = new GadgetHtmlNode("div", attribs);
+ parent.appendChild(new GadgetHtmlNode(" content\n"));
+ parent.appendChild(new GadgetHtmlNode("<br>"));
+ GadgetHtmlNode child1 = new GadgetHtmlNode("span", null);
+ child1.appendChild(new GadgetHtmlNode("hr", null));
+ parent.appendChild(child1);
+ parent.appendChild(new GadgetHtmlNode("\"after text\""));
+ GadgetHtmlNode child2 = new GadgetHtmlNode("p", null);
+ child2.appendChild(new GadgetHtmlNode("paragraph!"));
+ parent.appendChild(child2);
+ assertEquals("<div readonly> content\n<br><span><hr/>" +
+ "</span>"after text"<p>paragraph!</p></div>",
+ renderNode(parent));
+ }
+
+ private String renderNode(GadgetHtmlNode node) {
+ StringWriter sw = new StringWriter();
+ try {
+ node.render(sw);
+ } catch (IOException e) {
+ // Should never happen, but fail just in case.
+ fail("Unexpected IOException on StringWriter operation");
+ }
+ return sw.toString();
+ }
}