package at.ac.tuwien.infosys.jaxb;
import java.io.ByteArrayOutputStream;
import java.util.HashSet;
import java.util.Set;
import javax.xml.XMLConstants;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Simple DOM manipulation utilities.
*
* @author Waldemar Hummer
*/
public class XmlUtil {
public static String toString(Element element) {
return toString(element, false);
}
@SuppressWarnings("all")
/**
* This method needs to be synchronized, because of possible
* bug/synchronization issue:
* https://issues.apache.org/jira/browse/CXF-1560
* */
public static synchronized String toString(Element element, boolean indent) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
Transformer tr = TransformerFactory.newInstance().newTransformer();
tr.setOutputProperty(OutputKeys.METHOD, "xml");
if(indent) {
tr.setOutputProperty(
"{http://xml.apache.org/xslt}indent-amount", "2");
tr.setOutputProperty(OutputKeys.INDENT, "yes");
} else {
tr.setOutputProperty(OutputKeys.INDENT, "no");
}
tr.transform(new DOMSource(element), new StreamResult(baos));
} catch(Exception e) {
throw new RuntimeException(e);
}
String string = null;
byte[] bytes = baos.toByteArray();
string = new String(bytes);
bytes = null;
string = string
.replaceAll(
"<\\?xml version=\"1\\.0\" (encoding=\".*\")?( )*\\?>(\n)*",
"");
return string;
}
public static String toStringWithStrippedNamespaces(Element e) {
try {
RemoveUnusedNamespaces remove = new RemoveUnusedNamespaces();
Document d = e.getOwnerDocument();
remove.process(d);
return toString(d.getDocumentElement());
} catch (Exception e2) {
throw new RuntimeException(e2);
}
}
/* Based on:
* http://stackoverflow.com/a/9087074/2776806
*/
public static class RemoveUnusedNamespaces {
private interface ElementVisitor {
void visit(Element element);
}
public void process(Document document) {
final Set<String> namespaces = new HashSet<String>();
Element element = document.getDocumentElement();
traverse(element, new ElementVisitor() {
public void visit(Element element) {
String namespace = element.getNamespaceURI();
if (namespace == null)
namespace = "";
namespaces.add(namespace);
NamedNodeMap attributes = element.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Node node = attributes.item(i);
if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(node.getNamespaceURI()))
continue;
String prefix;
if (XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI.equals(node.getNamespaceURI())) {
if ("type".equals(node.getLocalName())) {
String value = node.getNodeValue();
if (value.contains(":"))
prefix = value.substring(0, value.indexOf(":"));
else
prefix = null;
} else {
continue;
}
} else {
prefix = node.getPrefix();
}
namespace = element.lookupNamespaceURI(prefix);
if (namespace == null)
namespace = "";
namespaces.add(namespace);
}
}
});
traverse(element, new ElementVisitor() {
public void visit(Element element) {
Set<String> removeLocalNames = new HashSet<String>();
NamedNodeMap attributes = element.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Node node = attributes.item(i);
if (!XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(node.getNamespaceURI()))
continue;
if (namespaces.contains(node.getNodeValue()))
continue;
removeLocalNames.add(node.getLocalName());
}
for (String localName : removeLocalNames)
element.removeAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, localName);
}
});
}
private final void traverse(Element element, ElementVisitor visitor) {
visitor.visit(element);
NodeList children = element.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
if (node.getNodeType() != Node.ELEMENT_NODE)
continue;
traverse((Element) node, visitor);
}
}
}
}