/*******************************************************************************
* Copyright (c) 2008 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.swt.tools.internal;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class DOMWriter {
static String ENCONDING = "UTF8";
PrintStream out;
String[] attributeFilter;
String[] idAttributes;
String nodeFilter;
public DOMWriter(PrintStream out) {
this.out = new PrintStream(out);
}
String nodeName(Node node) {
// TODO use getLocalName()?
return node.getNodeName();
}
boolean filter(Attr attr) {
if (attributeFilter == null) return false;
String name = attr.getNodeName();
for (int i = 0; i < attributeFilter.length; i++) {
if (name.matches(attributeFilter[i])) return false;
}
return true;
}
Node getIDAttribute(Node node) {
NamedNodeMap attributes = node.getAttributes();
if (attributes == null) return null;
String[] names = idAttributes;
for (int i = 0; i < names.length; i++) {
Node nameAttrib = attributes.getNamedItem(names[i]);
if (nameAttrib != null) return nameAttrib;
}
return null;
}
void print(String str) {
out.print(str);
}
void println() {
out.println();
}
public void print(Node node) {
print(node, 0);
}
public void print(Node node, int level) {
if (node == null)
return;
int type = node.getNodeType();
switch (type) {
case Node.DOCUMENT_NODE: {
print("<?xml version=\"1.0\" encoding=\"");
print(ENCONDING);
print("\"?>");
println();
print(((Document) node).getDocumentElement());
break;
}
case Node.ELEMENT_NODE: {
Attr attrs[] = sort(node.getAttributes());
String name = nodeName(node);
boolean isArg = name.equals("arg");
boolean gen = isArg || name.equals("retval");
for (int i = 0; i < attrs.length && !gen; i++) {
Attr attr = attrs[i];
if (nodeName(attr).startsWith(nodeFilter)) gen = true;
}
if (!gen) break;
for (int i = 0; i < level; i++) print("\t");
print("<");
print(name);
for (int i = 0; i < attrs.length; i++) {
Attr attr = attrs[i];
if (isArg && "name".equals(attr.getNodeName())) continue;
if (filter(attr)) continue;
print(" ");
print(nodeName(attr));
print("=\"");
print(normalize(attr.getNodeValue()));
print("\"");
}
print(">");
NodeList children = node.getChildNodes();
if (children != null) {
int len = children.getLength();
ArrayList<Node> nodes = new ArrayList<Node>();
for (int i = 0; i < len; i++) {
Node child = children.item(i);
if (child.getNodeType() == Node.ELEMENT_NODE) nodes.add(child);
}
int count = nodes.size();
Collections.sort(nodes, new Comparator<Node>() {
public int compare(Node a, Node b) {
String nameA = a.getNodeName();
String nameB = b.getNodeName();
if ("arg".equals(nameA)) {
return 0;
} else {
int result = nameA.compareTo(nameB);
if (result == 0) {
Node idA = getIDAttribute(a);
Node idB = getIDAttribute(b);
if (idA == null || idB == null) return 0;
return idA.getNodeValue().compareTo(idB.getNodeValue());
}
return result;
}
}
});
if (count > 0) println();
for (int i = 0; i < count; i++) {
print(nodes.get(i), level + 1);
}
if (count > 0) {
for (int i = 0; i < level; i++) print("\t");
}
}
print("</");
print(nodeName(node));
print(">");
println();
break;
}
}
out.flush();
}
Attr[] sort(NamedNodeMap attrs) {
if (attrs == null)
return new Attr[0];
Attr result[] = new Attr[attrs.getLength()];
for (int i = 0; i < result.length; i++) {
result[i] = (Attr) attrs.item(i);
}
Arrays.sort(result, new Comparator<Node>() {
public int compare(Node arg0, Node arg1) {
return nodeName(arg0).compareTo(nodeName(arg1));
}
});
return result;
}
String normalize(String s) {
if (s == null) return "";
StringBuffer str = new StringBuffer();
for (int i = 0, length = s.length(); i < length; i++) {
char ch = s.charAt(i);
switch (ch) {
case '"': str.append("\""); break;
case '\r':
case '\n':
// FALL THROUGH
default: str.append(ch);
}
}
return str.toString();
}
public void setNodeFilter(String filter) {
nodeFilter = filter;
}
public void setAttributeFilter(String[] filter) {
attributeFilter = filter;
}
public void setIDAttributes(String[] ids) {
idAttributes = ids;
}
}