package org.nate.internal.jsoup; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.jsoup.nodes.Element; import org.jsoup.nodes.Node; import org.jsoup.nodes.TextNode; import org.jsoup.parser.Tag; import org.jsoup.select.Selector.SelectorParseException; import org.nate.encoder.NateDocument; import org.nate.encoder.NateNode; import org.nate.exception.BadCssExpressionException; // Aaaarrrgggg... what a horrible inheritance hierarchy I have created! public class JsoupBackedNateDocumentFragment extends JsoupBackedAbstactDocument implements NateDocument { private Element pseudoRoot; public JsoupBackedNateDocumentFragment(List<? extends Node> nodes) { this(wrapInPseudoRoot(new ArrayList<Node>(nodes))); } public JsoupBackedNateDocumentFragment(Element pseudoRoot) { this.pseudoRoot = pseudoRoot; } @Override public NateDocument copy() { return new JsoupBackedNateDocumentFragment(pseudoRoot.clone()); } @Override protected List<Element> findMatchingElements(String selector) { try { List<Element> elements = new ArrayList<Element>(); for (Node node : getJsoupNodes()) { if (node instanceof Element) { elements.addAll(((Element) node).select(selector)); } } return elements; } catch (SelectorParseException e) { throw new BadCssExpressionException(e); } } @Override public void removeAttribute(String attributeName) { throw new IllegalStateException("Internal error."); } @Override public String render() { StringBuilder result = new StringBuilder(); for (Node node : getJsoupNodes()) { result.append(node.outerHtml()); } return result.toString(); } @Override public void replaceChildren(NateDocument newChildrenSource) { if (!(newChildrenSource instanceof JsoupBackedNateDocumentFragment)) { throw new IllegalStateException( "Internal Error. Expected JsoupBackedNateDocumentFragment, but got: " + newChildrenSource); } Collection<Node> newChildren = ((JsoupBackedAbstractNode)newChildrenSource).getJsoupNodes(); pseudoRoot = createPseudoRootElement(); for (Node newNode : newChildren) { pseudoRoot.appendChild(newNode.clone()); } } @Override public void replaceWith(List<NateNode> newNateNodes) { this.pseudoRoot = createPseudoRootElement(); for (NateNode newNode : newNateNodes) { Collection<Node> jsoupNodes = ((JsoupBackedAbstractNode)newNode.copy()).getJsoupNodes(); for (Node jsoupNode : jsoupNodes) { pseudoRoot.appendChild(jsoupNode.clone()); } } } @Override public void setAttribute(String name, String value) { throw new IllegalStateException("Internal error."); } @Override public void setTextContent(String text) { this.pseudoRoot = createPseudoRootElement(); this.pseudoRoot.appendChild(new TextNode(text, JsoupBackedNateDocumentFactory.BASE_URI)); } @Override Collection<Node> getJsoupNodes() { return this.pseudoRoot.childNodes(); } private static Element wrapInPseudoRoot(List<? extends Node> nodes) { Element result = createPseudoRootElement(); for (Node node : nodes) { result.appendChild(node); } return result; } private static Element createPseudoRootElement() { return new Element(Tag.valueOf("section"), JsoupBackedNateDocumentFactory.BASE_URI); } }