Author: lryan
Date: Tue Nov 18 13:51:41 2008
New Revision: 718725

URL: http://svn.apache.org/viewvc?rev=718725&view=rev
Log:
Convert gadget rendering rewriter to DOM
Ensure parsed documents always contain a body element 

Modified:
    
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlParser.java
    
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoHtmlParser.java
    
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/RenderingContentRewriter.java
    
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/RenderingContentRewriterTest.java

Modified: 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlParser.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlParser.java?rev=718725&r1=718724&r2=718725&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlParser.java
 (original)
+++ 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlParser.java
 Tue Nov 18 13:51:41 2008
@@ -71,6 +71,12 @@
             document.createElement("head"),
             document.getDocumentElement().getFirstChild());
       }
+      // If body not found the document was entirely empty. Create the
+      // element anyway
+      if (DomUtil.getFirstNamedChildNode(document.getDocumentElement(), 
"body") == null) {
+        document.getDocumentElement().appendChild(
+            document.createElement("body"));
+      }
       if (shouldCache) {
         documentCache.addElement(key, document);
       }

Modified: 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoHtmlParser.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoHtmlParser.java?rev=718725&r1=718724&r2=718725&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoHtmlParser.java
 (original)
+++ 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoHtmlParser.java
 Tue Nov 18 13:51:41 2008
@@ -71,6 +71,8 @@
   private Document parseFragment(String source) throws SAXException, 
IOException {
     InputSource input = new InputSource(new StringReader(source));
     DOMFragmentParser parser = new DOMFragmentParser();
+    parser.setProperty("http://cyberneko.org/html/properties/names/elems";, 
"default");
+
 
     Document htmlDoc = documentProvider.createDocument(null, null, null);
     DocumentFragment fragment = htmlDoc.createDocumentFragment();

Modified: 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/RenderingContentRewriter.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/RenderingContentRewriter.java?rev=718725&r1=718724&r2=718725&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/RenderingContentRewriter.java
 (original)
+++ 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/RenderingContentRewriter.java
 Tue Nov 18 13:51:41 2008
@@ -33,6 +33,7 @@
 import org.apache.shindig.gadgets.UrlGenerator;
 import org.apache.shindig.gadgets.http.HttpRequest;
 import org.apache.shindig.gadgets.http.HttpResponse;
+import org.apache.shindig.gadgets.parse.DomUtil;
 import org.apache.shindig.gadgets.preload.PreloadException;
 import org.apache.shindig.gadgets.preload.Preloads;
 import org.apache.shindig.gadgets.rewrite.ContentRewriter;
@@ -46,21 +47,25 @@
 import org.apache.shindig.gadgets.spec.UserPref;
 import org.apache.shindig.gadgets.spec.View;
 
+import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import com.google.inject.Inject;
 
 import org.json.JSONException;
 import org.json.JSONObject;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
 
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 /**
  * Produces a valid HTML document for the gadget output, automatically 
inserting appropriate HTML
@@ -80,20 +85,12 @@
  */
 public class RenderingContentRewriter implements ContentRewriter {
   private static final Logger LOG = 
Logger.getLogger(RenderingContentRewriter.class.getName());
-  static final Pattern DOCUMENT_SPLIT_PATTERN = Pattern.compile(
-      "(.*)<head>(.*?)<\\/head>(?:.*)<body(.*?)>(.*?)<\\/body>(?:.*)", 
Pattern.DOTALL |
-      Pattern.CASE_INSENSITIVE);
-  static final int BEFORE_HEAD_GROUP = 1;
-  static final int HEAD_GROUP = 2;
-  static final int BODY_ATTRIBUTES_GROUP = 3;
-  static final int BODY_GROUP = 4;
+
   static final String DEFAULT_HEAD_CONTENT =
-      "<style type=\"text/css\">" +
       "body,td,div,span,p{font-family:arial,sans-serif;}" +
       "a {color:#0000cc;}a:visited {color:#551a8b;}" +
       "a:active {color:#ff0000;}" +
-      "body{margin: 0px;padding: 0px;background-color:white;}" +
-      "</style>";
+      "body{margin: 0px;padding: 0px;background-color:white;}";
   static final String INSERT_BASE_ELEMENT_KEY = "gadgets.insertBaseElement";
   static final String FEATURES_KEY = "gadgets.features";
 
@@ -123,19 +120,50 @@
 
   public RewriterResults rewrite(Gadget gadget, MutableContent mutableContent) 
{
     try {
-      GadgetContent content = createGadgetContent(gadget, mutableContent);
+      Element head = (Element)DomUtil.getFirstNamedChildNode(
+          mutableContent.getDocument().getDocumentElement(), "head");
+
+      // Remove all the elements currently in head and add them back after we 
inject content
+      List<Node> existingHeadContent = Lists.newArrayList();
+      NodeList children = head.getChildNodes();
+      for (int i = 0; i < children.getLength(); i++) {
+        existingHeadContent.add(children.item(i));
+      }
+      for (Node n : existingHeadContent) {
+        head.removeChild(n);
+      }
+
+      Element defaultStyle = head.getOwnerDocument().createElement("style");
+      defaultStyle.setAttribute("type", "text/css");
+      head.appendChild(defaultStyle);
+      defaultStyle.appendChild(defaultStyle.getOwnerDocument().
+          createTextNode(DEFAULT_HEAD_CONTENT));
+
+      injectBaseTag(gadget, head);
+      injectFeatureLibraries(gadget, head);
 
-      injectBaseTag(gadget, content);
-      injectFeatureLibraries(gadget, content);
       // This can be one script block.
-      content.appendHead("<script>");
-      injectMessageBundles(gadget, content);
-      injectDefaultPrefs(gadget, content);
-      injectPreloads(gadget, content);
-      content.appendHead("</script>");
-      injectOnLoadHandlers(content);
-      // TODO: Use preloads when RenderedGadget gets promoted to Gadget.
-      mutableContent.setContent(finalizeDocument(gadget, content));
+      Element mainScriptTag = head.getOwnerDocument().createElement("script");
+      injectMessageBundles(gadget, mainScriptTag);
+      injectDefaultPrefs(gadget, mainScriptTag);
+      injectPreloads(gadget, mainScriptTag);
+      head.appendChild(mainScriptTag);
+
+      Element body = (Element)DomUtil.getFirstNamedChildNode(
+          mutableContent.getDocument().getDocumentElement(), "body");
+      
+      LocaleSpec localeSpec = gadget.getLocale();
+      if (localeSpec != null) {
+        body.setAttribute("dir", localeSpec.getLanguageDirection());
+      }
+
+      injectOnLoadHandlers(body);
+
+      for (Node n : existingHeadContent) {
+        head.appendChild(n);
+      }
+
+      MutableContent.notifyEdit(mutableContent.getDocument());
       return RewriterResults.notCacheable();
     } catch (GadgetException e) {
       // TODO: Rewriter interface needs to be modified to handle 
GadgetException or
@@ -144,7 +172,7 @@
     }
   }
 
-  private void injectBaseTag(Gadget gadget, GadgetContent content) {
+  private void injectBaseTag(Gadget gadget, Node headTag) {
     GadgetContext context = gadget.getContext();
     if ("true".equals(containerConfig.get(context.getContainer(), 
INSERT_BASE_ELEMENT_KEY))) {
       Uri base = gadget.getSpec().getUrl();
@@ -152,18 +180,23 @@
       if (view != null && view.getHref() != null) {
         base = view.getHref();
       }
-      content.appendHead("<base href='" + base + "'/>");
+      Element baseTag = headTag.getOwnerDocument().createElement("base");
+      baseTag.setAttribute("href", base.toString());
+      headTag.appendChild(baseTag);
     }
   }
 
-  private void injectOnLoadHandlers(GadgetContent content) {
-    content.appendBody("<script>gadgets.util.runOnLoadHandlers();</script>");
+  private void injectOnLoadHandlers(Node bodyTag) {
+    Element onloadScript = bodyTag.getOwnerDocument().createElement("script");
+    bodyTag.appendChild(onloadScript);
+    onloadScript.appendChild(bodyTag.getOwnerDocument().createTextNode(
+        "gadgets.util.runOnLoadHandlers();"));
   }
 
   /**
    * Injects javascript libraries needed to satisfy feature dependencies.
    */
-  private void injectFeatureLibraries(Gadget gadget, GadgetContent content) 
throws GadgetException {
+  private void injectFeatureLibraries(Gadget gadget, Node headTag) throws 
GadgetException {
     // TODO: If there isn't any js in the document, we can skip this. 
Unfortunately, that means
     // both script tags (easy to detect) and event handlers (much more 
complex).
     GadgetContext context = gadget.getContext();
@@ -176,12 +209,14 @@
       forced = Sets.newHashSet(forcedLibs.split(":"));
     }
 
-    String externFmt = "<script src=\"%s\"></script>";
 
     // Forced libs are always done first.
     if (!forced.isEmpty()) {
       String jsUrl = urlGenerator.getBundledJsUrl(forced, context);
-      content.appendHead(String.format(externFmt, jsUrl));
+      Element libsTag = headTag.getOwnerDocument().createElement("script");
+      libsTag.setAttribute("src", jsUrl.toString());
+      headTag.appendChild(libsTag);
+
       // Forced transitive deps need to be added as well so that they don't 
get pulled in twice.
       // TODO: Figure out a clean way to avoid having to call getFeatures 
twice.
       for (GadgetFeature dep : featureRegistry.getFeatures(forced)) {
@@ -200,12 +235,14 @@
       for (JsLibrary library : feature.getJsLibraries(RenderingContext.GADGET, 
container)) {
         if (library.getType().equals(JsLibrary.Type.URL)) {
           if (inlineJs.length() > 0) {
-            content.appendHead("<script>")
-                   .appendHead(inlineJs)
-                   .appendHead("</script>");
+            Element inlineTag = 
headTag.getOwnerDocument().createElement("script");
+            headTag.appendChild(inlineTag);
+            
inlineTag.appendChild(headTag.getOwnerDocument().createTextNode(inlineJs.toString()));
             inlineJs.setLength(0);
           }
-          content.appendHead(String.format(externFmt, library.getContent()));
+          Element referenceTag = 
headTag.getOwnerDocument().createElement("script");
+          referenceTag.setAttribute("src", library.getContent());
+          headTag.appendChild(referenceTag);
         } else {
           if (!forced.contains(feature.getName())) {
             // already pulled this file in from the shared contents.
@@ -223,9 +260,9 @@
     inlineJs.append(getLibraryConfig(gadget, features));
 
     if (inlineJs.length() > 0) {
-      content.appendHead("<script>")
-             .appendHead(inlineJs)
-             .appendHead("</script>");
+      Element inlineTag = headTag.getOwnerDocument().createElement("script");
+      headTag.appendChild(inlineTag);
+      
inlineTag.appendChild(headTag.getOwnerDocument().createTextNode(inlineJs.toString()));
     }
   }
 
@@ -332,21 +369,23 @@
    * Injects message bundles into the gadget output.
    * @throws GadgetException If we are unable to retrieve the message bundle.
    */
-  private void injectMessageBundles(Gadget gadget, GadgetContent content) 
throws GadgetException {
+  private void injectMessageBundles(Gadget gadget, Node scriptTag) throws 
GadgetException {
     GadgetContext context = gadget.getContext();
     MessageBundle bundle = messageBundleFactory.getBundle(
         gadget.getSpec(), context.getLocale(), context.getIgnoreCache());
 
     String msgs = new JSONObject(bundle.getMessages()).toString();
-    content.appendHead("gadgets.Prefs.setMessages_(")
-           .appendHead(msgs)
-           .appendHead(");");
+
+    Text text = 
scriptTag.getOwnerDocument().createTextNode("gadgets.Prefs.setMessages_(");
+    text.appendData(msgs.toString());
+    text.appendData(");");
+    scriptTag.appendChild(text);
   }
 
   /**
    * Injects default values for user prefs into the gadget output.
    */
-  private void injectDefaultPrefs(Gadget gadget, GadgetContent content) {
+  private void injectDefaultPrefs(Gadget gadget, Node scriptTag) {
     JSONObject defaultPrefs = new JSONObject();
     try {
       for (UserPref up : gadget.getSpec().getUserPrefs()) {
@@ -355,9 +394,10 @@
     } catch (JSONException e) {
       // Never happens. Name is required (cannot be null). Default value is a 
String.
     }
-    content.appendHead("gadgets.Prefs.setDefaultPrefs_(")
-           .appendHead(defaultPrefs.toString())
-           .appendHead(");");
+    Text text = 
scriptTag.getOwnerDocument().createTextNode("gadgets.Prefs.setDefaultPrefs_(");
+    text.appendData(defaultPrefs.toString());
+    text.appendData(");");
+    scriptTag.appendChild(text);
   }
 
   /**
@@ -365,7 +405,7 @@
    *
    * If preloading fails for any reason, we just output an empty object.
    */
-  private void injectPreloads(Gadget gadget, GadgetContent content) {
+  private void injectPreloads(Gadget gadget, Node scriptTag) {
     JSONObject preload = new JSONObject();
     Preloads preloads = gadget.getPreloads();
 
@@ -380,107 +420,9 @@
         throw new RuntimeException(e);
       }
     }
-
-    content.appendHead("gadgets.io.preloaded_=")
-           .appendHead(preload.toString())
-           .appendHead(";");
-  }
-
-  /**
-   * Produces GadgetContent by parsing the document into 3 pieces (head, body, 
and tail). If the
-   */
-  private GadgetContent createGadgetContent(Gadget gadget, MutableContent 
mutableContent) {
-    String doc = mutableContent.getContent();
-    // Quick check for full document tags
-    String head = doc.substring(0, Math.min(150, doc.length()));
-    if (head.contains("<HTML") || head.contains("<html")) {
-      Matcher matcher = DOCUMENT_SPLIT_PATTERN.matcher(doc);
-      if (matcher.matches()) {
-        GadgetContent content = new GadgetContent();
-        content.appendHead(matcher.group(BEFORE_HEAD_GROUP))
-               .appendHead("<head>");
-
-        content.appendBody(matcher.group(HEAD_GROUP))
-               .appendBody("</head>")
-               .appendBody(createBodyTag(gadget, 
matcher.group(BODY_ATTRIBUTES_GROUP)))
-               .appendBody(matcher.group(BODY_GROUP));
-
-        content.appendTail("</body></html>");
-        return content;
-      } else {
-        return makeDefaultContent(gadget, mutableContent);
-      }
-    }
-    return makeDefaultContent(gadget, mutableContent);
-  }
-
-  /**
-   * Inserts basic content for a gadget. Used when the content does not 
contain a valid html doc.
-   */
-  private GadgetContent makeDefaultContent(Gadget gadget, MutableContent 
mutableContent) {
-    GadgetContent content = new GadgetContent();
-    content.appendHead("<html><head>");
-    content.appendHead(DEFAULT_HEAD_CONTENT);
-    content.appendBody("</head>");
-    content.appendBody(createBodyTag(gadget, ""));
-    content.appendBody(mutableContent.getContent());
-    content.appendTail("</body></html>");
-    return content;
-  }
-
-  /**
-   * Produces the default body tag, inserting language direction as needed.
-   */
-  private String createBodyTag(Gadget gadget, String extra) {
-    LocaleSpec localeSpec = gadget.getLocale();
-    if (localeSpec == null) {
-      return "<body" + extra + ">";
-    } else {
-      return "<body" + extra + " dir='" + localeSpec.getLanguageDirection() + 
"'>";
-    }
-  }
-
-  /**
-   * Produces a final document for the gadget's content.
-   */
-  private String finalizeDocument(Gadget gadget, GadgetContent content) {
-    return content.assemble();
-  }
-
-  private static class GadgetContent {
-    private final StringBuilder head = new StringBuilder();
-    private final StringBuilder body = new StringBuilder();
-    private final StringBuilder tail = new StringBuilder();
-
-    GadgetContent appendHead(CharSequence content) {
-      head.append(content);
-      return this;
-    }
-
-    GadgetContent appendBody(CharSequence content) {
-      body.append(content);
-      return this;
-    }
-
-    GadgetContent appendTail(CharSequence content) {
-      tail.append(content);
-      return this;
-    }
-
-    /**
-     * @return The final content for the gadget.
-     */
-    String assemble() {
-      return new StringBuilder(head.length() + body.length() + tail.length())
-          .append(head)
-          .append(body)
-          .append(tail)
-          .toString();
-    }
-
-    @Override
-    public String toString() {
-      return assemble();
-    }
+    Text text = 
scriptTag.getOwnerDocument().createTextNode("gadgets.io.preloaded_=");
+    text.appendData(preload.toString());
+    text.appendData(";");
+    scriptTag.appendChild(text);
   }
 }

Modified: 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/RenderingContentRewriterTest.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/RenderingContentRewriterTest.java?rev=718725&r1=718724&r2=718725&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/RenderingContentRewriterTest.java
 (original)
+++ 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/RenderingContentRewriterTest.java
 Tue Nov 18 13:51:41 2008
@@ -19,6 +19,7 @@
 package org.apache.shindig.gadgets.render;
 
 import org.apache.shindig.common.ContainerConfig;
+import org.apache.shindig.common.PropertiesModule;
 import org.apache.shindig.common.uri.Uri;
 import org.apache.shindig.common.xml.XmlUtil;
 import org.apache.shindig.gadgets.Gadget;
@@ -29,17 +30,14 @@
 import org.apache.shindig.gadgets.JsLibrary;
 import org.apache.shindig.gadgets.MessageBundleFactory;
 import org.apache.shindig.gadgets.UrlGenerator;
+import org.apache.shindig.gadgets.parse.GadgetHtmlParser;
+import org.apache.shindig.gadgets.parse.ParseModule;
 import org.apache.shindig.gadgets.preload.NullPreloads;
 import org.apache.shindig.gadgets.preload.PreloadException;
 import org.apache.shindig.gadgets.preload.PreloadedData;
 import org.apache.shindig.gadgets.preload.Preloads;
-import static 
org.apache.shindig.gadgets.render.RenderingContentRewriter.BEFORE_HEAD_GROUP;
-import static 
org.apache.shindig.gadgets.render.RenderingContentRewriter.BODY_ATTRIBUTES_GROUP;
-import static 
org.apache.shindig.gadgets.render.RenderingContentRewriter.BODY_GROUP;
 import static 
org.apache.shindig.gadgets.render.RenderingContentRewriter.DEFAULT_HEAD_CONTENT;
-import static 
org.apache.shindig.gadgets.render.RenderingContentRewriter.DOCUMENT_SPLIT_PATTERN;
 import static 
org.apache.shindig.gadgets.render.RenderingContentRewriter.FEATURES_KEY;
-import static 
org.apache.shindig.gadgets.render.RenderingContentRewriter.HEAD_GROUP;
 import static 
org.apache.shindig.gadgets.render.RenderingContentRewriter.INSERT_BASE_ELEMENT_KEY;
 import org.apache.shindig.gadgets.rewrite.MutableContent;
 import org.apache.shindig.gadgets.spec.GadgetSpec;
@@ -51,6 +49,8 @@
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
 
 import static org.easymock.EasyMock.expect;
 import org.easymock.classextension.EasyMock;
@@ -86,12 +86,24 @@
 
   private FakeGadgetFeatureRegistry featureRegistry;
   private RenderingContentRewriter rewriter;
+  private GadgetHtmlParser parser;
+
+  static final Pattern DOCUMENT_SPLIT_PATTERN = Pattern.compile(
+      "(.*)<head>(.*?)<\\/head>(?:.*)<body(.*?)>(.*?)<\\/body>(?:.*)", 
Pattern.DOTALL |
+      Pattern.CASE_INSENSITIVE);
+
+  static final int BEFORE_HEAD_GROUP = 1;
+  static final int HEAD_GROUP = 2;
+  static final int BODY_ATTRIBUTES_GROUP = 3;
+  static final int BODY_GROUP = 4;
 
   @Before
   public void setUp() throws Exception {
     featureRegistry = new FakeGadgetFeatureRegistry();
     rewriter
         = new RenderingContentRewriter(messageBundleFactory, config, 
featureRegistry, urlGenerator);
+    Injector injector = Guice.createInjector(new ParseModule(), new 
PropertiesModule());
+    parser = injector.getInstance(GadgetHtmlParser.class);
   }
 
   private Gadget makeGadgetWithSpec(String gadgetXml) throws GadgetException {
@@ -108,7 +120,7 @@
   }
 
   private String rewrite(Gadget gadget, String content) {
-    MutableContent mc = new MutableContent(null, content);
+    MutableContent mc = new MutableContent(parser, content);
     assertEquals(0, rewriter.rewrite(gadget, mc).getCacheTtl());
     return mc.getContent();
   }
@@ -123,7 +135,8 @@
 
     Matcher matcher = DOCUMENT_SPLIT_PATTERN.matcher(rewritten);
     assertTrue("Output is not valid HTML.", matcher.matches());
-    assertTrue("Missing opening html tag", 
matcher.group(BEFORE_HEAD_GROUP).contains("<html>"));
+    assertTrue("Missing opening html tag", matcher.group(BEFORE_HEAD_GROUP).
+        toLowerCase().contains("<html>"));
     assertTrue("Default head content is missing.",
         matcher.group(HEAD_GROUP).contains(DEFAULT_HEAD_CONTENT));
     // Not very accurate -- could have just been user prefs.
@@ -137,9 +150,9 @@
 
   @Test
   public void completeDocument() throws Exception {
-    String docType = "<![DOCTYPE html]>";
-    String head = "<script src='foo.js'></script><style 
type='text/css'>body{color:red;}</style>";
-    String bodyAttr = " onload='foo();'";
+    String docType = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 
Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\";>";
+    String head = "<script src=\"foo.js\"></script><style 
type=\"text/css\">body{color:red;}</style>";
+    String bodyAttr = " onload=\"foo();\"";
     String body = "hello, world.";
     String doc = new StringBuilder()
         .append(docType)
@@ -201,7 +214,7 @@
     String rewritten = rewrite(gadget, "");
 
     assertTrue("Bi-directional locale settings not preserved.",
-        rewritten.contains("<body dir='rtl'>"));
+        rewritten.contains("<body dir=\"rtl\">"));
   }
 
   private Set<String> getInjectedScript(String content) {
@@ -308,7 +321,7 @@
     control.replay();
 
     String rewritten = rewrite(gadget,
-        "<html><head><script 
src='foo.js'></script></head><body>hello</body></html>");
+        "<html><head><script 
src=\"foo.js\"></script></head><body>hello</body></html>");
 
     Matcher matcher = DOCUMENT_SPLIT_PATTERN.matcher(rewritten);
     assertTrue("Output is not valid HTML.", matcher.matches());
@@ -316,7 +329,7 @@
     String headContent = matcher.group(HEAD_GROUP);
 
     // Locate user script.
-    int userPosition = headContent.indexOf("<script src='foo.js'></script>");
+    int userPosition = headContent.indexOf("<script src=\"foo.js\"></script>");
 
     // Anything else here, we added.
     int ourPosition = headContent.indexOf("<script>");
@@ -624,7 +637,7 @@
     Matcher matcher = DOCUMENT_SPLIT_PATTERN.matcher(content);
     assertTrue("Output is not valid HTML.", matcher.matches());
     Pattern baseElementPattern
-        = Pattern.compile("(?:.*)<base href='(.*?)'\\/>(?:.*)", 
Pattern.DOTALL);
+        = Pattern.compile("(?:.*)<base href=\"(.*?)\">(?:.*)", Pattern.DOTALL);
     Matcher baseElementMatcher = 
baseElementPattern.matcher(matcher.group(HEAD_GROUP));
     assertTrue("base element missing from head of document.", 
baseElementMatcher.matches());
     return baseElementMatcher.group(1);


Reply via email to