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=\"&lt;script&amp;&quot;data&quot;&gt;\"/>",
+                 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("&lt;script&amp;&quot;data'&gt;",
+                 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&lt;br&gt;<span><hr/>" +
+                 "</span>&quot;after text&quot;<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();
+  }
 }


Reply via email to