// Copyright 2010 Google Inc.
//
// Licensed 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.npr.android.util;
import android.util.Log;
import org.npr.api.IterableNodeList;
import org.w3c.dom.Node;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class NodeUtils {
private static final String LOG_TAG = NodeUtils.class.getName();
private static boolean getTextContentAvailable = true;
private static Method getTextContentMethod = null;
private final static int MAX_RECURSION_DEPTH = 10;
/**
* Node#getTextContent() is only available in Froyo and later.
* Call getTextContent if it exists else use local implementation
* @param node
* @return text content of this node and its descendant
*/
public static String getTextContent(Node node) {
if (getTextContentAvailable && getTextContentMethod == null) {
try {
getTextContentMethod = Node.class.getMethod(
"getTextContent", (Class[]) null );
} catch (NoSuchMethodException nsme) {
// failure, must be older device
getTextContentAvailable = false;
}
}
if (getTextContentAvailable) {
try {
return (String) getTextContentMethod.invoke(node);
} catch (IllegalArgumentException e1) {
getTextContentAvailable = false;
} catch (IllegalAccessException e1) {
getTextContentAvailable = false;
} catch (InvocationTargetException e1) {
getTextContentAvailable = false;
}
}
// getTextContent doesn't exist.
return getTextContentImpl(node, 0);
}
/**
* implementation based on Javadoc description of getTextContent
* @param node
* @return text content of this node and its descendant
*/
private static String getTextContentImpl(Node node, int recursionDepth) {
// should never happen but don't allow too much recursion
if (recursionDepth > MAX_RECURSION_DEPTH) {
Log.d(LOG_TAG, "too much recursion!");
return "";
}
switch (node.getNodeType()) {
case Node.TEXT_NODE:
case Node.CDATA_SECTION_NODE:
case Node.COMMENT_NODE:
case Node.PROCESSING_INSTRUCTION_NODE:
return node.getNodeValue();
case Node.ELEMENT_NODE:
case Node.ATTRIBUTE_NODE:
case Node.ENTITY_NODE:
case Node.ENTITY_REFERENCE_NODE:
case Node.DOCUMENT_FRAGMENT_NODE:
StringBuffer value = new StringBuffer();
for (Node childNode: new IterableNodeList(node.getChildNodes())) {
int childNodeType = childNode.getNodeType();
if (childNodeType != Node.COMMENT_NODE
&& childNodeType != Node.PROCESSING_INSTRUCTION_NODE) {
value.append(getTextContentImpl(childNode, recursionDepth + 1));
}
}
return value.toString();
}
Log.d(LOG_TAG, "unexpected node type: " + node.getNodeType());
return null;
}
}