/*
* (C) Copyright 2006-2007 Nuxeo SA (http://nuxeo.com/) and others.
*
* 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.
*
* Contributors:
* Max Stepanov
*
* $Id$
*/
package org.nuxeo.ecm.platform.domsync.core;
import java.text.MessageFormat;
import java.util.Stack;
import java.util.StringTokenizer;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* @author Max Stepanov
*/
public class DOMUtil {
private DOMUtil() {
}
public static String computeNodeXPath(Node base, Node node) {
if (base.isSameNode(node)) {
return "/";
}
short nodeType = node.getNodeType();
String subpath;
if (nodeType == Node.ELEMENT_NODE || nodeType == Node.TEXT_NODE) {
String localName = node.getLocalName().toLowerCase();
int pos = 0;
Node sibling = node.getPreviousSibling();
while (sibling != null) {
if (sibling.getNodeType() == nodeType) {
if (localName.equals(sibling.getLocalName().toLowerCase())) {
++pos;
}
}
sibling = sibling.getPreviousSibling();
}
if (nodeType == Node.TEXT_NODE) {
localName = "text()";
}
if (pos == 0) {
subpath = localName;
} else {
subpath = MessageFormat.format("{0}[{1}]", localName, new Integer(pos));
}
} else {
System.err.println("Unsupported type " + nodeType);
subpath = "unknown";
}
Node parent = node.getParentNode();
if (base.isSameNode(parent)) {
return '/' + subpath;
} else {
return computeNodeXPath(base, parent) + '/' + subpath;
}
}
public static Node findNodeByXPath(Node base, String xpath) {
if ("/".equals(xpath)) {
return base;
}
Node node = base;
StringTokenizer tok = new StringTokenizer(xpath, "/");
while (tok.hasMoreTokens()) {
String subpath = tok.nextToken();
String localName;
int nodePos = 0;
int index = subpath.indexOf('[');
if (index > 0) {
localName = subpath.substring(0, index).toLowerCase();
nodePos = Integer.parseInt(subpath.substring(index + 1, subpath.indexOf(']')));
} else {
localName = subpath.toLowerCase();
}
short nodeType = Node.ELEMENT_NODE;
if ("text()".equals(localName)) {
nodeType = Node.TEXT_NODE;
localName = "";
}
node = node.getFirstChild();
int pos = 0;
while (node != null) {
if (node.getNodeType() == nodeType && localName.equals(node.getLocalName().toLowerCase())) {
if (pos == nodePos) {
break;
}
++pos;
}
node = node.getNextSibling();
}
}
return node;
/*
* try { XPathFactory factory = XPathFactory.newInstance(); XPath xpath = factory.newXPath(); XPathExpression
* expr = xpath.compile(path); return (Node) expr.evaluate(document, XPathConstants.NODE); } catch
* (XPathExpressionException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (DOMException
* e) { // TODO Auto-generated catch block e.printStackTrace(); }
*/
}
public static Node getNodeAtPosition(Node parent, int offset) {
if (offset < 0) {
return null;
} else if (offset == 0) {
return parent.getFirstChild();
}
NodeList nodes = parent.getChildNodes();
int count = nodes.getLength();
if (offset < count) {
return nodes.item(offset);
}
return null;
}
public static int getNodePosition(Node node) {
int pos = -1;
while (node != null) {
++pos;
node = node.getPreviousSibling();
}
return pos;
}
public static String getElementOuterNoChildren(Element element) {
StringBuilder sb = new StringBuilder();
String tagName = element.getTagName();
sb.append('<').append(tagName);
NamedNodeMap attrs = element.getAttributes();
int count = attrs.getLength();
for (int i = 0; i < count; ++i) {
Attr attr = (Attr) attrs.item(i);
if (attr.getSpecified()) {
sb.append(' ').append(attr.getName()).append("=\"").append(attr.getValue()).append('"');
}
}
if ("br".equals(tagName.toLowerCase())) {
sb.append("/>");
} else {
sb.append("></").append(tagName).append('>');
}
return sb.toString();
}
public static String dumpTree(Node node) {
StringBuilder sb = new StringBuilder();
Stack<Node> stack = new Stack<Node>();
int level = 0;
while (node != null || !stack.isEmpty()) {
if (node == null) {
do {
node = stack.pop();
--level;
} while (node == null && !stack.isEmpty());
continue;
}
for (int i = 0; i < level; ++i) {
sb.append(' ');
}
sb.append(node.getNodeName()).append(" <").append(node.getNodeValue()).append(">\n");
stack.push(node.getNextSibling());
node = node.getFirstChild();
++level;
}
return sb.toString();
}
}