Accidentally committed three CLs in one. I'll revert and submit one-by-one.
In any case, none of this infrastructure links with existing functionality
at this point: it's all new.

On Thu, Aug 14, 2008 at 6:27 PM, <[EMAIL PROTECTED]> wrote:

> Author: johnh
> Date: Thu Aug 14 18:27:23 2008
> New Revision: 686101
>
> URL: http://svn.apache.org/viewvc?rev=686101&view=rev
> Log:
> Framework for generating a parse tree of HTML and CSS content.
>
> These interfaces are defined in order to cleanly separate parsing logic
> from classes that manipulate a given parse tree (HTML or CSS). The parse
> tree objects are intended to be only as complex as is needed for the vast
> majority of content rewriting manipulation. They provide structure but
> no more semantics (validation, CSS resolution, etc.) than that.
>
>
> Added:
>
>  
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/
>
>  
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetCssDeclaration.java
>
>  
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetCssParser.java
>
>  
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetCssRule.java
>
>  
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlAttribute.java
>
>  
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlNode.java
>
>  
> 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/ParsedCssDeclaration.java
>
>  
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/ParsedCssRule.java
>
>  
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/ParsedHtmlAttribute.java
>
>  
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/ParsedHtmlNode.java
>
>  
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/caja/
>
>  
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/caja/CajaCssParser.java
>
>  
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/caja/CajaHtmlParser.java
>
> Added:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetCssDeclaration.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetCssDeclaration.java?rev=686101&view=auto
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetCssDeclaration.java
> (added)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetCssDeclaration.java
> Thu Aug 14 18:27:23 2008
> @@ -0,0 +1,72 @@
> +/**
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements. See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership. The ASF licenses this file
> + * to you 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 org.apache.shindig.gadgets.parse;
> +
> +/**
> + * Mutable wrapper around a [EMAIL PROTECTED] ParsedCssDeclaration}.
> + * Used by rewriting to manipulate parsed gadget CSS, and
> + * to separate parsing from manipulation code.
> + */
> +public class GadgetCssDeclaration {
> +  private String name;
> +  private String value;
> +
> +  /**
> +   * Construct a mutable attribute out of an immutable parsed one.
> +   * @param source Parsed CSS declaration
> +   */
> +  public GadgetCssDeclaration(ParsedCssDeclaration source) {
> +    this.name = source.getName();
> +    this.value = source.getValue();
> +  }
> +
> +  /**
> +   * Construct a mutable CSS declaration from a name/value pair.
> +   * @param name Name of attribute
> +   * @param value Value of attribute
> +   */
> +  public GadgetCssDeclaration(String name, String value) {
> +    this.name = name;
> +    this.value = value;
> +  }
> +
> +  /**
> +   * @return Name of the HTML attribute
> +   */
> +  public String getName() {
> +    return name;
> +  }
> +
> +  /**
> +   * @return Value of the HTML attribute
> +   */
> +  public String getValue() {
> +    return value;
> +  }
> +
> +  /**
> +   * Only provide an API for setting value. To set
> +   * a new attribute a developer can simply create
> +   * a new one. To replace, the developer can delete
> +   * the existing one before doing so.
> +   * @param value New HTML attribute value.
> +   */
> +  public void setValue(String value) {
> +    this.value = value;
> +  }
> +}
>
> Added:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetCssParser.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetCssParser.java?rev=686101&view=auto
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetCssParser.java
> (added)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetCssParser.java
> Thu Aug 14 18:27:23 2008
> @@ -0,0 +1,34 @@
> +/**
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements. See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership. The ASF licenses this file
> + * to you 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 org.apache.shindig.gadgets.parse;
> +
> +import org.apache.shindig.gadgets.GadgetException;
> +
> +import java.util.List;
> +
> +/**
> + * Parser for CSS content. Parsing may be done on a fully-formed
> + * CSS block, such as the contents of a CSS file or &lt;style&gt; block.
> + *
> + * [EMAIL PROTECTED] ParsedCssRule} and [EMAIL PROTECTED] 
> ParsedCssDeclaration} for additional
> + * parsing requirements and semantics.
> + */
> +public interface GadgetCssParser {
> +  public List<ParsedCssRule> parse(String css) throws GadgetException;
> +  public List<ParsedCssDeclaration> parseInline(String style) throws
> GadgetException;
> +}
>
> Added:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetCssRule.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetCssRule.java?rev=686101&view=auto
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetCssRule.java
> (added)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetCssRule.java
> Thu Aug 14 18:27:23 2008
> @@ -0,0 +1,144 @@
> +/**
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements. See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership. The ASF licenses this file
> + * to you 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 org.apache.shindig.gadgets.parse;
> +
> +import java.util.Collections;
> +import java.util.HashMap;
> +import java.util.LinkedList;
> +import java.util.List;
> +import java.util.Map;
> +import java.util.Set;
> +
> +/**
> + * Mutable wrapper around a [EMAIL PROTECTED] ParsedCssRule}.
> + * Used by rewriting to manipulate parsed gadget CSS, and
> + * to separate parsing from manipulation code.
> + */
> +public class GadgetCssRule {
> +  private final List<String> selectors;
> +  private final Map<String, String> declarations;
> +
> +  /**
> +   * Create a new [EMAIL PROTECTED] GadgetCssRule} from a [EMAIL PROTECTED] 
> ParsedCssRule}
> +   * @param source Parsed CSS rule
> +   */
> +  public GadgetCssRule(ParsedCssRule source) {
> +    this();
> +    for (String selector : source.getSelectors()) {
> +      addSelector(selector, null);
> +    }
> +
> +    // Last decl with a given key "wins" - duplicates are therefore
> ignored.
> +    for (ParsedCssDeclaration decl : source.getDeclarations()) {
> +      setDeclaration(decl.getName(), decl.getValue());
> +    }
> +  }
> +
> +  /**
> +   * Create a new, blank rule. At least one selector must be added
> +   * for the rule to be valid (and serializable).
> +   */
> +  public GadgetCssRule() {
> +    selectors = new LinkedList<String>();
> +    declarations = new HashMap<String, String>();
> +  }
> +
> +  /**
> +   * Adds a new selector after the provided entry. Selector order in a
> given
> +   * rule is significant in CSS.
> +   * @param selector Selector to add (will be automatically trimmed)
> +   * @param before Selector key after which to add new, null for list end
> +   * @return Whether or not the selector was freshly added
> +   */
> +  public boolean addSelector(String selector, String before) {
> +    selector = selector.trim();
> +    int selIx = selectors.indexOf(selector);
> +    if (selIx >= 0) {
> +      return false;
> +    }
> +    if (before == null) {
> +      return selectors.add(selector);
> +    }
> +    int befIx = selectors.indexOf(before);
> +    if (befIx >= 0) {
> +      selectors.add(befIx, selector);
> +    } else {
> +      selectors.add(selector);
> +    }
> +    return true;
> +  }
> +
> +  /**
> +   * @param selector Selector to remove
> +   * @return Whether or not the selector was present and removed
> +   */
> +  public boolean removeSelector(String selector) {
> +    return selectors.remove(selector);
> +  }
> +
> +  /**
> +   * @param selector Selector whose presence in the rule to test
> +   * @return Whether or not the selector exists in the rule
> +   */
> +  public boolean hasSelector(String selector) {
> +    return selectors.contains(selector);
> +  }
> +
> +  /**
> +   * @return Unmodifiable list of selectors
> +   */
> +  public List<String> getSelectors() {
> +    return Collections.unmodifiableList(selectors);
> +  }
> +
> +  /**
> +   * Add a declaration by key/value. Key is trimmed.
> +   * @param key Declaration key, either new or replaced
> +   * @param value Declaration value, either new or replaced
> +   */
> +  public void setDeclaration(String key, String value) {
> +    key = key.trim();
> +    declarations.put(key, value);
> +  }
> +
> +  /**
> +   * @param key Key for the declaration to remove.
> +   * @return Whether or not the declaration existed and was removed
> +   */
> +  public boolean removeDeclaration(String key) {
> +    key = key.trim();
> +    return declarations.remove(key) != null;
> +  }
> +
> +  /**
> +   * Get a given declaration's value by key.
> +   * @param key Key for the declaration
> +   * @return Declaration's value, or null if not present
> +   */
> +  public String getDeclarationValue(String key) {
> +    key = key.trim();
> +    return declarations.get(key);
> +  }
> +
> +  /**
> +   * @return Unmodifiable set of existing declaration keys.
> +   */
> +  public Set<String> getDeclarationKeys() {
> +    return Collections.unmodifiableSet(declarations.keySet());
> +  }
> +}
>
> Added:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlAttribute.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlAttribute.java?rev=686101&view=auto
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlAttribute.java
> (added)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlAttribute.java
> Thu Aug 14 18:27:23 2008
> @@ -0,0 +1,72 @@
> +/**
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements. See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership. The ASF licenses this file
> + * to you 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 org.apache.shindig.gadgets.parse;
> +
> +/**
> + * Mutable wrapper around a [EMAIL PROTECTED] ParsedHtmlAttribute}.
> + * Used by rewriting to manipulate a parsed gadget DOM, and
> + * to separate parsing from manipulation code.
> + */
> +public class GadgetHtmlAttribute {
> +  private String name;
> +  private String value;
> +
> +  /**
> +   * Construct a mutable attribute out of an immutable parsed one.
> +   * @param source Parsed HTML attribute
> +   */
> +  public GadgetHtmlAttribute(ParsedHtmlAttribute source) {
> +    this.name = source.getName();
> +    this.value = source.getValue();
> +  }
> +
> +  /**
> +   * Construct a mutable attribute from a name/value pair.
> +   * @param name Name of attribute
> +   * @param value Value of attribute
> +   */
> +  public GadgetHtmlAttribute(String name, String value) {
> +    this.name = name;
> +    this.value = value;
> +  }
> +
> +  /**
> +   * @return Name of the HTML attribute
> +   */
> +  public String getName() {
> +    return name;
> +  }
> +
> +  /**
> +   * @return Value of the HTML attribute
> +   */
> +  public String getValue() {
> +    return value;
> +  }
> +
> +  /**
> +   * Only provide an API for setting value. To set
> +   * a new attribute a developer can simply create
> +   * a new one. To replace, the developer can delete
> +   * the existing one before doing so.
> +   * @param value New HTML attribute value.
> +   */
> +  public void setValue(String value) {
> +    this.value = value;
> +  }
> +}
>
> Added:
> 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=686101&view=auto
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlNode.java
> (added)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlNode.java
> Thu Aug 14 18:27:23 2008
> @@ -0,0 +1,287 @@
> +/**
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements. See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership. The ASF licenses this file
> + * to you 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 org.apache.shindig.gadgets.parse;
> +
> +import java.util.Collections;
> +import java.util.HashMap;
> +import java.util.LinkedList;
> +import java.util.List;
> +import java.util.Map;
> +import java.util.Set;
> +
> +/**
> + * Mutable wrapper around a [EMAIL PROTECTED] ParsedHtmlNode}.
> + * Used by rewriting to manipulate a parsed gadget DOM, and
> + * to separate parsing from manipulation code. Essentially
> + * a lightweight DOM1-style object.
> + */
> +public class GadgetHtmlNode {
> +  private final NodeType type;
> +  private GadgetHtmlNode parentNode;
> +  private String tagName;
> +  private Map<String, String> attributes;
> +  private List<GadgetHtmlNode> children;
> +  private String text;
> +
> +  private enum NodeType {
> +    TAG, TEXT
> +  }
> +
> +  /**
> +   * Construct a mutable HTML node from a parsed one.
> +   * @param parsed HTML node object from parser.
> +   */
> +  public GadgetHtmlNode(ParsedHtmlNode parsed) {
> +    if (parsed.getText() == null) {
> +      // Tag type
> +      type = NodeType.TAG;
> +      parentNode = null;
> +      tagName = parsed.getTagName();
> +      attributes = new HashMap<String, String>();
> +      for (ParsedHtmlAttribute attrib : parsed.getAttributes()) {
> +        setAttribute(attrib.getName(), attrib.getValue());
> +      }
> +      children = new LinkedList<GadgetHtmlNode>();
> +      for (ParsedHtmlNode node: parsed.getChildren()) {
> +        appendChild(new GadgetHtmlNode(node));
> +      }
> +    } else {
> +      type = NodeType.TEXT;
> +      setText(parsed.getText());
> +    }
> +  }
> +
> +  /**
> +   * Construct a tag-type HTML node.
> +   * @param tagName Tag name for new node, must not be null.
> +   * @param attributes Name/value pairs for new attributes, or null if
> none.
> +   */
> +  public GadgetHtmlNode(String tag, String[][] attribs) {
> +    type = NodeType.TAG;
> +    tagName = tag;
> +    attributes = new HashMap<String, String>();
> +    if (attribs != null) {
> +      for (String[] attrib : attribs) {
> +        if (attrib == null || attrib.length != 2) {
> +          throw new UnsupportedOperationException(
> +              "Coding error: Invalid GadgetHtmlNode creation");
> +        }
> +        setAttribute(attrib[0], attrib[1]);
> +      }
> +    }
> +    children = new LinkedList<GadgetHtmlNode>();
> +  }
> +
> +  /**
> +   * Construct a text-type HTML node.
> +   * @param text Textual contents of new node.
> +   */
> +  public GadgetHtmlNode(String text) {
> +    type = NodeType.TEXT;
> +    setText(text);
> +  }
> +
> +  /**
> +   * @return True if the node is text type
> +   */
> +  public boolean isText() {
> +    return type == NodeType.TEXT;
> +  }
> +
> +  /**
> +   * @return Tag name for the HTML node.
> +   */
> +  public String getTagName() {
> +    validateNodeType(NodeType.TAG);
> +    return tagName;
> +  }
> +
> +  /**
> +   * @param newTag New tag name to set for the node
> +   * @return True if the tag name was set, false if invalid
> +   */
> +  public boolean setTagName(String newTag) {
> +    validateNodeType(NodeType.TAG);
> +    if (tagName != null) {
> +      newTag = newTag.trim();
> +      if (newTag.matches("[\\w\\-_:]+")) {
> +        this.tagName = newTag;
> +        return true;
> +      }
> +    }
> +    return false;
> +  }
> +
> +  /**
> +   * Retrieve an attribute by key.
> +   * @param key Attribute key to look up.
> +   * @return Value associated with key, or null if none.
> +   */
> +  public String getAttributeValue(String key) {
> +    validateNodeType(NodeType.TAG);
> +    return attributes.get(key);
> +  }
> +
> +  /**
> +   * Remove an attribute by key.
> +   * @param key Key for attribute to remove.
> +   * @return Whether or not an attribute with that key was removed.
> +   */
> +  public boolean removeAttribute(String key) {
> +    validateNodeType(NodeType.TAG);
> +    boolean hasBefore = hasAttribute(key);
> +    attributes.remove(key);
> +    return hasBefore && !hasAttribute(key);
> +  }
> +
> +  /**
> +   * Set an attribute's key/value.
> +   * @param key Attribute key.
> +   * @param value Attribute value.
> +   * @return Whether or not the set operation succeeded.
> +   */
> +  public boolean setAttribute(String key, String value) {
> +    validateNodeType(NodeType.TAG);
> +    String putKey = validateAttributeKey(key);
> +    if (putKey == null) {
> +      return false;
> +    }
> +    attributes.put(putKey, value);
> +    return true;
> +  }
> +
> +  /**
> +   * @param key Key whose existence to test in the attribute set
> +   * @return Whether or not the node has an attribute for the given key
> +   */
> +  public boolean hasAttribute(String key) {
> +    validateNodeType(NodeType.TAG);
> +    return attributes.containsKey(key);
> +  }
> +
> +  /**
> +   * @return Immutable set of attribute keys.
> +   */
> +  public Set<String> getAttributeKeys() {
> +    validateNodeType(NodeType.TAG);
> +    return Collections.unmodifiableSet(attributes.keySet());
> +  }
> +
> +  // DOM-like node management helpers
> +  /**
> +   * Append a new node to this node's children.
> +   * @param node New node to append.
> +   */
> +  public void appendChild(GadgetHtmlNode node) {
> +    insertBefore(node, null);
> +  }
> +
> +  /**
> +   * Insert a new node before another given node. If the relative
> +   * node is not found or null, insert the new node at the end of
> +   * this node's children.
> +   * @param node New node to insert.
> +   * @param before Node before which to insert [EMAIL PROTECTED] node}.
> +   */
> +  public void insertBefore(GadgetHtmlNode node, GadgetHtmlNode before) {
> +    validateNodeType(NodeType.TAG);
> +    node.setParentNode(this);
> +    if (before == null) {
> +      children.add(node);
> +      return;
> +    }
> +    int befIx = children.indexOf(before);
> +    if (befIx >= 0) {
> +      children.add(befIx, node);
> +    } else {
> +      children.add(node);
> +    }
> +  }
> +
> +  /**
> +   * Remove the given node from the tree.
> +   * @param node Node to remove.
> +   * @return Whether or not the node was removed.
> +   */
> +  public boolean removeChild(GadgetHtmlNode node) {
> +    validateNodeType(NodeType.TAG);
> +
> +    // For good measure, dissociate from parent
> +    node.setParentNode(null);
> +    return children.remove(node);
> +  }
> +
> +  /**
> +   * Returns this nodes parent, or null if none exists.
> +   * @return
> +   */
> +  public GadgetHtmlNode getParentNode() {
> +    return parentNode;
> +  }
> +
> +  // Internal helper: sets parent for tree-node management
> +  private void setParentNode(GadgetHtmlNode parent) {
> +    parentNode = parent;
> +  }
> +
> +  /**
> +   * Returns an unmodifiable list of current child nodes.
> +   * @return
> +   */
> +  public List<GadgetHtmlNode> getChildren() {
> +    validateNodeType(NodeType.TAG);
> +    return Collections.unmodifiableList(children);
> +  }
> +
> +  /**
> +   * @return Text for this node if text-type.
> +   */
> +  public String getText() {
> +    validateNodeType(NodeType.TEXT);
> +    return text;
> +  }
> +
> +  /**
> +   * Set new text value for the node.
> +   * @param text New text value for the node.
> +   */
> +  public void setText(String text) {
> +    validateNodeType(NodeType.TEXT);
> +    this.text = text;
> +  }
> +
> +  // Helper that cleans up and validates an attribute key
> +  private String validateAttributeKey(String key) {
> +    if (key == null) {
> +      return null;
> +    }
> +    key = key.trim();
> +    if (!key.matches("[\\w\\d_\\-:]+")) {
> +      return null;
> +    }
> +    return key;
> +  }
> +
> +  // Helper that enforces correct API usage by type
> +  private void validateNodeType(NodeType expected) {
> +    if (type != expected) {
> +      throw new UnsupportedOperationException("Code error: " +
> +          "Attempted " + expected + " operation on node of type " + type);
> +    }
> +  }
> +}
>
> Added:
> 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=686101&view=auto
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlParser.java
> (added)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlParser.java
> Thu Aug 14 18:27:23 2008
> @@ -0,0 +1,34 @@
> +/**
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements. See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership. The ASF licenses this file
> + * to you 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 org.apache.shindig.gadgets.parse;
> +
> +import org.apache.shindig.gadgets.GadgetException;
> +
> +import java.util.List;
> +
> +/**
> + * Parser for arbitrary HTML content. The content may simply be a
> + * fragment or snippet of HTML rather than a fully-structured Document,
> + * so the interface returns a list of [EMAIL PROTECTED] ParsedHtmlNode} 
> objects
> + * rather than a single top-level item.
> + *
> + * [EMAIL PROTECTED] ParsedHtmlNode} for parsing details
> + */
> +public interface GadgetHtmlParser {
> +  public List<ParsedHtmlNode> parse(String source) throws GadgetException;
> +}
>
> Added:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/ParsedCssDeclaration.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/ParsedCssDeclaration.java?rev=686101&view=auto
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/ParsedCssDeclaration.java
> (added)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/ParsedCssDeclaration.java
> Thu Aug 14 18:27:23 2008
> @@ -0,0 +1,36 @@
> +/**
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements. See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership. The ASF licenses this file
> + * to you 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 org.apache.shindig.gadgets.parse;
> +
> +/**
> + * Interface for a single CSS declaration, eg. color: blue; in:
> + * #id {
> + *   color: blue;
> + * }
> + */
> +public interface ParsedCssDeclaration {
> +  /**
> +   * @return Name of the declaration
> +   */
> +  public String getName();
> +
> +  /**
> +   * @return Value of the declaration
> +   */
> +  public String getValue();
> +}
>
> Added:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/ParsedCssRule.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/ParsedCssRule.java?rev=686101&view=auto
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/ParsedCssRule.java
> (added)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/ParsedCssRule.java
> Thu Aug 14 18:27:23 2008
> @@ -0,0 +1,37 @@
> +/**
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements. See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership. The ASF licenses this file
> + * to you 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 org.apache.shindig.gadgets.parse;
> +
> +import java.util.List;
> +
> +/**
> + * Simplified interface for a parsed CSS rule.
> + *
> + * For rule:
> + * #id1, .class1 {
> + *   color: blue;
> + *   font-size: 10 em;
> + * }
> + *
> + * Selectors are "#id1" and ".class1", and ParsedCssDeclarations
> + * are name/value "color"/"blue" and "font-size"/"10 em".
> + */
> +public interface ParsedCssRule {
> +  public List<String> getSelectors();
> +  public List<ParsedCssDeclaration> getDeclarations();
> +}
>
> Added:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/ParsedHtmlAttribute.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/ParsedHtmlAttribute.java?rev=686101&view=auto
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/ParsedHtmlAttribute.java
> (added)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/ParsedHtmlAttribute.java
> Thu Aug 14 18:27:23 2008
> @@ -0,0 +1,33 @@
> +/**
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements. See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership. The ASF licenses this file
> + * to you 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 org.apache.shindig.gadgets.parse;
> +
> +/**
> + * Simple name/value representation of a parsed HTML attribute.
> + */
> +public interface ParsedHtmlAttribute {
> +  /**
> +   * @return HTML attribute name.
> +   */
> +  public String getName();
> +
> +  /**
> +   * @return HTML attribute value.
> +   */
> +  public String getValue();
> +}
>
> Added:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/ParsedHtmlNode.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/ParsedHtmlNode.java?rev=686101&view=auto
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/ParsedHtmlNode.java
> (added)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/ParsedHtmlNode.java
> Thu Aug 14 18:27:23 2008
> @@ -0,0 +1,56 @@
> +/**
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements. See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership. The ASF licenses this file
> + * to you 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 org.apache.shindig.gadgets.parse;
> +
> +import java.util.List;
> +
> +/**
> + * Simplified interface wrapping a unit of parsed HTML.
> + * Each [EMAIL PROTECTED] ParsedHtmlNode} is either text-type or
> + * tag-type. The following snippet of HTML provides an example of both
> types:
> + *
> + * &lt;div id="foo"&gt;content&lt;div&gt;
> + *
> + * This corresponds to a single top-level [EMAIL PROTECTED] ParsedHtmlNode}
> + * where [EMAIL PROTECTED] getTagName()} returns "div" and has one
> + * [EMAIL PROTECTED] ParsedHtmlAttribute} with N/V "id"/"foo", [EMAIL 
> PROTECTED] getText()}
> + * is [EMAIL PROTECTED] null}, and has one [EMAIL PROTECTED] ParsedHtmlNode} 
> child. That
> + * child in turn has [EMAIL PROTECTED] getText()} equal to "content", with
> + * all other methods returning [EMAIL PROTECTED] null}.
> + */
> +public interface ParsedHtmlNode {
> +  /**
> +   * @return Tag name for an HTML element, or null if text-type.
> +   */
> +  public String getTagName();
> +
> +  /**
> +   * @return List of HTML attributes on an element, or null if text-type
> +   */
> +  public List<ParsedHtmlAttribute> getAttributes();
> +
> +  /**
> +   * @return List of child nodes of the HTML element, or null if text-type
> +   */
> +  public List<ParsedHtmlNode> getChildren();
> +
> +  /**
> +   * @return Unescaped text as contained in an HTML string; null if
> tag-type
> +   */
> +  public String getText();
> +}
>
> Added:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/caja/CajaCssParser.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/caja/CajaCssParser.java?rev=686101&view=auto
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/caja/CajaCssParser.java
> (added)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/caja/CajaCssParser.java
> Thu Aug 14 18:27:23 2008
> @@ -0,0 +1,176 @@
> +/**
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements. See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership. The ASF licenses this file
> + * to you 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 org.apache.shindig.gadgets.parse.caja;
> +
> +import com.google.caja.lexer.CharProducer;
> +import com.google.caja.lexer.CssLexer;
> +import com.google.caja.lexer.CssTokenType;
> +import com.google.caja.lexer.InputSource;
> +import com.google.caja.lexer.ParseException;
> +import com.google.caja.lexer.Token;
> +import com.google.caja.lexer.TokenConsumer;
> +import com.google.caja.lexer.TokenQueue;
> +import com.google.caja.parser.css.CssParser;
> +import com.google.caja.parser.css.CssTree;
> +import com.google.caja.reporting.MessageContext;
> +import com.google.caja.reporting.RenderContext;
> +import com.google.caja.util.Criterion;
> +
> +import org.apache.shindig.gadgets.GadgetException;
> +import org.apache.shindig.gadgets.parse.GadgetCssParser;
> +import org.apache.shindig.gadgets.parse.ParsedCssDeclaration;
> +import org.apache.shindig.gadgets.parse.ParsedCssRule;
> +
> +import java.io.StringReader;
> +import java.net.URI;
> +import java.net.URISyntaxException;
> +import java.util.ArrayList;
> +import java.util.List;
> +
> +public class CajaCssParser implements GadgetCssParser {
> +
> +  public List<ParsedCssRule> parse(String css) throws GadgetException {
> +    if (css.matches("\\s*")) {
> +      return new ArrayList<ParsedCssRule>(0);
> +    }
> +
> +    CssParser parser = getParser(css);
> +    CssTree.StyleSheet stylesheet = null;
> +
> +    try {
> +      stylesheet = parser.parseStyleSheet();
> +    } catch (ParseException e) {
> +      throw new GadgetException(GadgetException.Code.CSS_PARSE_ERROR, e);
> +    }
> +
> +    ArrayList<ParsedCssRule> rules =
> +        new ArrayList<ParsedCssRule>(stylesheet.children().size());
> +    for (CssTree node : stylesheet.children()) {
> +      if (node instanceof CssTree.RuleSet) {
> +        rules.add(new CajaParsedCssRule((CssTree.RuleSet)node));
> +      }
> +    }
> +
> +    return rules;
> +  }
> +
> +  public List<ParsedCssDeclaration> parseInline(String style)
> +      throws GadgetException {
> +    if (style.matches("\\s*")) {
> +      return new ArrayList<ParsedCssDeclaration>();
> +    }
> +
> +    CssParser parser = getParser(style);
> +    CssTree.DeclarationGroup declGroup = null;
> +
> +    try {
> +      declGroup = parser.parseDeclarationGroup();
> +    } catch (ParseException e) {
> +      throw new GadgetException(GadgetException.Code.CSS_PARSE_ERROR, e);
> +    }
> +
> +    List<ParsedCssDeclaration> attributes =
> +        new ArrayList<ParsedCssDeclaration>(declGroup.children().size());
> +    for (CssTree node : declGroup.children()) {
> +      if (node instanceof CssTree.Declaration) {
> +        CssTree.Declaration decl = (CssTree.Declaration)node;
> +        if (decl.getProperty() != null) {
> +          attributes.add(new CajaParsedCssDeclaration(decl));
> +        }
> +      }
> +    }
> +
> +    return attributes;
> +  }
> +
> +  private CssParser getParser(String content) {
> +    InputSource source = null;
> +    try {
> +      source = new InputSource(new URI("http://dummy.com/";));
> +    } catch (URISyntaxException e) {
> +      // Never happens. Dummy URI needed to satisfy API.
> +      // We may want to pass in the gadget URI for auditing
> +      // purposes at some point.
> +    }
> +    CharProducer producer = CharProducer.Factory.create(new
> StringReader(content), source);
> +    CssLexer lexer = new CssLexer(producer);
> +    return new CssParser(new TokenQueue<CssTokenType>(
> +        lexer,
> +        source,
> +        new Criterion<Token<CssTokenType>>() {
> +          public boolean accept(Token<CssTokenType> tok) {
> +            return tok.type != CssTokenType.COMMENT
> +                && tok.type != CssTokenType.SPACE;
> +          }
> +        }));
> +  }
> +
> +  private static final String renderCssTreeElement(CssTree elem) {
> +    StringBuffer selBuffer = new StringBuffer();
> +    TokenConsumer tc = elem.makeRenderer(selBuffer, null);
> +    elem.render(new RenderContext(new MessageContext(), tc));
> +    return selBuffer.toString();
> +  }
> +
> +  private static class CajaParsedCssRule implements ParsedCssRule {
> +    private final List<ParsedCssDeclaration> attributes;
> +    private final List<String> selectors;
> +
> +    private CajaParsedCssRule(CssTree.RuleSet ruleSet) {
> +      attributes = new ArrayList<ParsedCssDeclaration>();
> +      selectors = new ArrayList<String>();
> +
> +      for (CssTree child : ruleSet.children()) {
> +        if (child instanceof CssTree.Selector) {
> +          selectors.add(renderCssTreeElement(child));
> +        } else if (child instanceof CssTree.Declaration) {
> +          CssTree.Declaration decl = (CssTree.Declaration)child;
> +          if (decl.getProperty() != null) {
> +            attributes.add(new CajaParsedCssDeclaration(decl));
> +          }
> +        }
> +      }
> +    }
> +
> +    public List<ParsedCssDeclaration> getDeclarations() {
> +      return attributes;
> +    }
> +
> +    public List<String> getSelectors() {
> +      return selectors;
> +    }
> +  }
> +
> +  private static class CajaParsedCssDeclaration implements
> ParsedCssDeclaration {
> +    private final String key;
> +    private final String value;
> +
> +    private CajaParsedCssDeclaration(CssTree.Declaration declaration) {
> +      key = declaration.getProperty().getPropertyName();
> +      value = renderCssTreeElement(declaration.getExpr());
> +    }
> +
> +    public String getName() {
> +      return key;
> +    }
> +
> +    public String getValue() {
> +      return value;
> +    }
> +  }
> +}
>
> Added:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/caja/CajaHtmlParser.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/caja/CajaHtmlParser.java?rev=686101&view=auto
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/caja/CajaHtmlParser.java
> (added)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/caja/CajaHtmlParser.java
> Thu Aug 14 18:27:23 2008
> @@ -0,0 +1,163 @@
> +/**
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements. See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership. The ASF licenses this file
> + * to you 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 org.apache.shindig.gadgets.parse.caja;
> +
> +import com.google.caja.lexer.CharProducer;
> +import com.google.caja.lexer.HtmlLexer;
> +import com.google.caja.lexer.HtmlTokenType;
> +import com.google.caja.lexer.InputSource;
> +import com.google.caja.lexer.ParseException;
> +import com.google.caja.lexer.TokenQueue;
> +import com.google.caja.parser.html.DomParser;
> +import com.google.caja.parser.html.DomTree;
> +import com.google.caja.reporting.MessageQueue;
> +import com.google.caja.reporting.SimpleMessageQueue;
> +
> +import org.apache.shindig.gadgets.GadgetException;
> +import org.apache.shindig.gadgets.parse.GadgetHtmlParser;
> +import org.apache.shindig.gadgets.parse.ParsedHtmlAttribute;
> +import org.apache.shindig.gadgets.parse.ParsedHtmlNode;
> +
> +import java.io.StringReader;
> +import java.net.URI;
> +import java.net.URISyntaxException;
> +import java.util.ArrayList;
> +import java.util.List;
> +
> +/**
> + * Caja-based implementation of a [EMAIL PROTECTED] GadgetHtmlParser}.
> + */
> +public class CajaHtmlParser implements GadgetHtmlParser {
> +
> +  /** [EMAIL PROTECTED] */
> +  public List<ParsedHtmlNode> parse(String source) throws GadgetException
> {
> +    // Wrap the whole thing in a top-level node to get full contents.
> +    DomParser parser = getParser("<html>" + source + "</html>");
> +
> +    DomTree domTree = null;
> +    try {
> +      domTree = parser.parseFragment();
> +    } catch (ParseException e) {
> +      throw new GadgetException(GadgetException.Code.CSS_PARSE_ERROR, e);
> +    }
> +
> +    List<ParsedHtmlNode> nodes =
> +        new ArrayList<ParsedHtmlNode>(domTree.children().size());
> +    for (DomTree child : domTree.children()) {
> +      nodes.add(new CajaParsedHtmlNode(child));
> +    }
> +    return nodes;
> +  }
> +
> +  public DomParser getParser(String content) {
> +    InputSource source = null;
> +    try {
> +      source = new InputSource(new URI("http://dummy.com/";));
> +    } catch (URISyntaxException e) {
> +      // Never happens. Dummy URI needed to satisfy API.
> +      // We may want to pass in the gadget URI for auditing
> +      // purposes at some point.
> +    }
> +    CharProducer producer = CharProducer.Factory.create(
> +        new StringReader(content), source);
> +    HtmlLexer lexer = new HtmlLexer(producer);
> +    MessageQueue mQueue = new SimpleMessageQueue();
> +    return new DomParser(new TokenQueue<HtmlTokenType>(lexer, source),
> false, mQueue);
> +  }
> +
> +  /**
> +   * [EMAIL PROTECTED] ParsedHtmlNode} implementation built using Caja 
> parsing
> primitives.
> +   */
> +  private static class CajaParsedHtmlNode implements ParsedHtmlNode {
> +    private final List<ParsedHtmlAttribute> attributes;
> +    private final List<ParsedHtmlNode> children;
> +    private final String name;
> +    private final String text;
> +
> +    private CajaParsedHtmlNode(DomTree elem) {
> +      if (elem instanceof DomTree.Tag) {
> +        DomTree.Tag tag = (DomTree.Tag)elem;
> +        attributes = new ArrayList<ParsedHtmlAttribute>();
> +        children = new ArrayList<ParsedHtmlNode>();
> +        name = tag.getTagName();
> +        text = null;
> +        for (DomTree child : elem.children()) {
> +          if (child instanceof DomTree.Attrib) {
> +            attributes.add(new
> CajaParsedHtmlAttribute((DomTree.Attrib)child));
> +          } else {
> +            children.add(new CajaParsedHtmlNode(child));
> +          }
> +        }
> +      } else if (elem instanceof DomTree.Text ||
> +                 elem instanceof DomTree.CData) {
> +        // DomTree.CData can theoretically occur since it's supported
> +        // in HTML5, but the implementation doesn't supply this yet.
> +        attributes = null;
> +        children = null;
> +        name = null;
> +        text = ((DomTree.Text)elem).getValue();
> +      } else {
> +        // This should never happen. The only remaining types are
> +        // DomTree.Fragment, which is simply a top-level container
> +        // that results from the DomTree.parseFragment() method,
> +        // and DomTree.Value, which is always a child of DomTree.Attrib.
> +        attributes = null;
> +        children = null;
> +        name = null;
> +        text = null;
> +      }
> +    }
> +
> +    public List<ParsedHtmlAttribute> getAttributes() {
> +      return attributes;
> +    }
> +
> +    public List<ParsedHtmlNode> getChildren() {
> +      return children;
> +    }
> +
> +    public String getTagName() {
> +      return name;
> +    }
> +
> +    public String getText() {
> +      return text;
> +    }
> +  }
> +
> +  /**
> +   * [EMAIL PROTECTED] ParsedHtmlAttribute} built from a Caja DomTree 
> primitive.
> +   */
> +  private static class CajaParsedHtmlAttribute implements
> ParsedHtmlAttribute {
> +    private final String name;
> +    private final String value;
> +
> +    private CajaParsedHtmlAttribute(DomTree.Attrib attrib) {
> +      name = attrib.getAttribName();
> +      value = attrib.getAttribValue();
> +    }
> +
> +    public String getName() {
> +      return name;
> +    }
> +
> +    public String getValue() {
> +      return value;
> +    }
> +  }
> +}
>
>
>

Reply via email to