diff options
author | Jesse Wilson <jessewilson@google.com> | 2010-02-23 15:23:26 -0800 |
---|---|---|
committer | Jesse Wilson <jessewilson@google.com> | 2010-02-23 17:56:48 -0800 |
commit | bda224da00c0372a7752b1304aeda98e2930c4af (patch) | |
tree | a28550992209058749a605e25ee35a48cd459964 /xml/src/main/java/org | |
parent | ea6435b142df4aaaf8854b3200b9f442b331f143 (diff) | |
download | libcore-bda224da00c0372a7752b1304aeda98e2930c4af.zip libcore-bda224da00c0372a7752b1304aeda98e2930c4af.tar.gz libcore-bda224da00c0372a7752b1304aeda98e2930c4af.tar.bz2 |
Implementing still more DOM API for text nodes.
- Text.isElementContentWhitespace()
- Text.getWholeText()
- Text.replaceWholeText()
Diffstat (limited to 'xml/src/main/java/org')
7 files changed, 107 insertions, 48 deletions
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/CDATASectionImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/CDATASectionImpl.java index 33e216a..b28c9da 100644 --- a/xml/src/main/java/org/apache/harmony/xml/dom/CDATASectionImpl.java +++ b/xml/src/main/java/org/apache/harmony/xml/dom/CDATASectionImpl.java @@ -31,7 +31,7 @@ import org.w3c.dom.Node; */ public class CDATASectionImpl extends TextImpl implements CDATASection { - CDATASectionImpl(DocumentImpl document, String data) { + public CDATASectionImpl(DocumentImpl document, String data) { super(document, data); } diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/CharacterDataImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/CharacterDataImpl.java index c39423c..6354747 100644 --- a/xml/src/main/java/org/apache/harmony/xml/dom/CharacterDataImpl.java +++ b/xml/src/main/java/org/apache/harmony/xml/dom/CharacterDataImpl.java @@ -51,6 +51,13 @@ public abstract class CharacterDataImpl extends LeafNodeImpl implements return buffer.toString(); } + /** + * Appends this node's text content to the given builder. + */ + public void appendDataTo(StringBuilder stringBuilder) { + stringBuilder.append(buffer); + } + public int getLength() { return buffer.length(); } diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/DOMImplementationImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/DOMImplementationImpl.java index 834cc47..1283eeb 100644 --- a/xml/src/main/java/org/apache/harmony/xml/dom/DOMImplementationImpl.java +++ b/xml/src/main/java/org/apache/harmony/xml/dom/DOMImplementationImpl.java @@ -31,7 +31,7 @@ import org.w3c.dom.DocumentType; * the DOM implementation can easily access them while maintaining the DOM tree * structure. */ -public class DOMImplementationImpl implements DOMImplementation { +public final class DOMImplementationImpl implements DOMImplementation { // Singleton instance. private static DOMImplementationImpl instance; diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java index c8819cb..b2f16d1 100644 --- a/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java +++ b/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java @@ -48,7 +48,7 @@ public class DocumentImpl extends InnerNodeImpl implements Document { private DOMImplementation domImplementation; - DocumentImpl(DOMImplementationImpl impl, String namespaceURI, + public DocumentImpl(DOMImplementationImpl impl, String namespaceURI, String qualifiedName, DocumentType doctype) { super(null); diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java index ebfdd52..24ed102 100644 --- a/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java +++ b/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java @@ -224,7 +224,6 @@ public abstract class NodeImpl implements Node { * account null arguments and the "*" special case. * * @param name The required name. - * @param wildcard TODO * @return True if and only if the actual name matches the required one. */ public boolean matchesName(String name, boolean wildcard) { @@ -238,7 +237,6 @@ public abstract class NodeImpl implements Node { * * @param namespaceURI The required namespace. * @param localName The required local name. - * @param wildcard TODO * @return True if and only if the actual namespace and local name match * the required pair of namespace and local name. */ @@ -309,7 +307,7 @@ public abstract class NodeImpl implements Node { removeChild(child); } // create a text node to hold the given content - if (textContent != null && textContent.length() != 0){ + if (textContent != null && textContent.length() != 0) { appendChild(getOwnerDocument().createTextNode(textContent)); } return; diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/TextImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/TextImpl.java index 5c9d123..3840ef4 100644 --- a/xml/src/main/java/org/apache/harmony/xml/dom/TextImpl.java +++ b/xml/src/main/java/org/apache/harmony/xml/dom/TextImpl.java @@ -32,7 +32,7 @@ import org.w3c.dom.Text; */ public class TextImpl extends CharacterDataImpl implements Text { - TextImpl(DocumentImpl document, String data) { + public TextImpl(DocumentImpl document, String data) { super(document, data); } @@ -46,7 +46,7 @@ public class TextImpl extends CharacterDataImpl implements Text { return Node.TEXT_NODE; } - public Text splitText(int offset) throws DOMException { + public final Text splitText(int offset) throws DOMException { Text newText = getOwnerDocument().createTextNode( substringData(offset, getLength() - offset)); deleteData(0, offset); @@ -61,15 +61,83 @@ public class TextImpl extends CharacterDataImpl implements Text { return this; } - public boolean isElementContentWhitespace() { - throw new UnsupportedOperationException(); // TODO + public final boolean isElementContentWhitespace() { + // Undefined because we don't validate. Whether whitespace characters + // constitute "element content whitespace" is defined by the containing + // element's declaration (DTD) and we don't parse that. + // TODO: wire this up when we support document validation + return false; } - public String getWholeText() { - throw new UnsupportedOperationException(); // TODO + public final String getWholeText() { + // TODO: support entity references. This code should expand through + // the child elements of entity references. + // http://code.google.com/p/android/issues/detail?id=6807 + + StringBuilder result = new StringBuilder(); + for (TextImpl n = firstTextNodeInCurrentRun(); n != null; n = n.nextTextNode()) { + n.appendDataTo(result); + } + return result.toString(); } - public Text replaceWholeText(String content) throws DOMException { - throw new UnsupportedOperationException(); // TODO + public final Text replaceWholeText(String content) throws DOMException { + // TODO: support entity references. This code should expand and replace + // the child elements of entity references. + // http://code.google.com/p/android/issues/detail?id=6807 + + Node parent = getParentNode(); + Text result = null; + + // delete all nodes in the current run of text... + for (TextImpl n = firstTextNodeInCurrentRun(); n != null; ) { + + // ...except the current node if we have content for it + if (n == this && content != null && content.length() > 0) { + setData(content); + result = this; + n = n.nextTextNode(); + + } else { + Node toRemove = n; // because removeChild() detaches siblings + n = n.nextTextNode(); + parent.removeChild(toRemove); + } + } + + return result; + } + + /** + * Returns the first text or CDATA node in the current sequence of text and + * CDATA nodes. + */ + private TextImpl firstTextNodeInCurrentRun() { + TextImpl firstTextInCurrentRun = this; + for (Node p = getPreviousSibling(); p != null; p = p.getPreviousSibling()) { + short nodeType = p.getNodeType(); + if (nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE) { + firstTextInCurrentRun = (TextImpl) p; + } else { + break; + } + } + return firstTextInCurrentRun; + } + + /** + * Returns the next sibling node if it exists and it is text or CDATA. + * Otherwise returns null. + */ + private TextImpl nextTextNode() { + Node nextSibling = getNextSibling(); + if (nextSibling == null) { + return null; + } + + short nodeType = nextSibling.getNodeType(); + return nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE + ? (TextImpl) nextSibling + : null; } } diff --git a/xml/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java b/xml/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java index 52240aa..ca2ff98 100644 --- a/xml/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java +++ b/xml/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java @@ -23,10 +23,14 @@ import java.util.StringTokenizer; import javax.xml.parsers.DocumentBuilder; +import org.apache.harmony.xml.dom.CDATASectionImpl; +import org.apache.harmony.xml.dom.DocumentImpl; +import org.apache.harmony.xml.dom.TextImpl; import org.kxml2.io.KXmlParser; import org.w3c.dom.Attr; import org.w3c.dom.DOMImplementation; import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.Text; @@ -49,7 +53,7 @@ import org.apache.harmony.xml.dom.DOMImplementationImpl; */ class DocumentBuilderImpl extends DocumentBuilder { - private static DOMImplementation dom = DOMImplementationImpl.getInstance(); + private static DOMImplementationImpl dom = DOMImplementationImpl.getInstance(); private boolean coalescing; @@ -72,25 +76,6 @@ class DocumentBuilderImpl extends DocumentBuilder { return dom; } - /** - * Reflects whether this DocumentBuilder is configured to ignore comments. - * - * @return True if and only if comments are ignored. - */ - public boolean isIgnoringComments() { - return ignoreComments; - } - - /** - * Reflects whether this DocumentBuilder is configured to ignore element - * content whitespace. - * - * @return True if and only if whitespace element content is ignored. - */ - public boolean isIgnoringElementContentWhitespace() { - return ignoreElementContentWhitespace; - } - @Override public boolean isNamespaceAware() { return namespaceAware; @@ -112,7 +97,10 @@ class DocumentBuilderImpl extends DocumentBuilder { throw new IllegalArgumentException(); } - Document document = newDocument(); + String namespaceURI = null; + String qualifiedName = null; + DocumentType doctype = null; + DocumentImpl document = new DocumentImpl(dom, namespaceURI, qualifiedName, doctype); try { KXmlParser parser = new KXmlParser(); @@ -189,7 +177,7 @@ class DocumentBuilderImpl extends DocumentBuilder { * @throws XmlPullParserException If a parsing error occurs. * @throws IOException If a general IO error occurs. */ - private void parse(XmlPullParser parser, Document document, Node node, + private void parse(XmlPullParser parser, DocumentImpl document, Node node, int endToken) throws XmlPullParserException, IOException { int token = parser.getEventType(); @@ -271,7 +259,7 @@ class DocumentBuilderImpl extends DocumentBuilder { * whitespace at all. */ if (!ignoreElementContentWhitespace) { - appendText(document, node, true, parser.getText()); + appendText(document, node, token, parser.getText()); } } else if (token == XmlPullParser.TEXT || token == XmlPullParser.CDSECT) { /* @@ -279,7 +267,7 @@ class DocumentBuilderImpl extends DocumentBuilder { * That's the easiest case. We simply take it and create a new text node, * or merge with an adjacent text node. */ - appendText(document, node, token == XmlPullParser.TEXT, parser.getText()); + appendText(document, node, token, parser.getText()); } else if (token == XmlPullParser.ENTITY_REF) { /* * Found an entity reference. If an entity resolver is @@ -294,7 +282,7 @@ class DocumentBuilderImpl extends DocumentBuilder { String replacement = resolveStandardEntity(entity); if (replacement != null) { - appendText(document, node, true, replacement); + appendText(document, node, token, replacement); } else { node.appendChild(document.createEntityReference(entity)); } @@ -380,17 +368,17 @@ class DocumentBuilderImpl extends DocumentBuilder { } /** - * @param isText true for a normal TextNode, false for a CDATA section. - * (If we're not coalescing, it matters which kind of node we put into the DOM.) + * @param token the XML pull parser token type, such as XmlPullParser.CDSECT + * or XmlPullParser.ENTITY_REF. */ - private void appendText(Document document, Node node, boolean isText, String text) { + private void appendText(DocumentImpl document, Node parent, int token, String text) { // Ignore empty runs. if (text.length() == 0) { return; } // Merge with any previous text node if possible. if (coalescing) { - Node lastChild = node.getLastChild(); + Node lastChild = parent.getLastChild(); if (lastChild != null && lastChild.getNodeType() == Node.TEXT_NODE) { Text textNode = (Text) lastChild; textNode.setData(textNode.getNodeValue() + text); @@ -398,11 +386,9 @@ class DocumentBuilderImpl extends DocumentBuilder { } } // Okay, we really do need a new text node - if (isText) { - node.appendChild(document.createTextNode(text)); - } else { - node.appendChild(document.createCDATASection(text)); - } + parent.appendChild(token == XmlPullParser.CDSECT + ? new CDATASectionImpl(document, text) + : new TextImpl(document, text)); } @Override |