/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jbpm.xml;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.logging.Logger;
import javax.xml.namespace.QName;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.jbpm.PvmException;
import org.w3c.dom.Attr;
import org.w3c.dom.CharacterData;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* convenience methods to make reading org.w3c.dom models easier.
*
* @author Tom Baeyens
*/
public abstract class XmlUtil {
private static Logger log = Logger.getLogger(XmlUtil.class.getName());
public static List<Element> elements(Element element, String tagName) {
List<Element> elements = null;
NodeList nodeList = element.getChildNodes();
if (nodeList != null) {
for (int i = 0; i < nodeList.getLength(); i++) {
Node child = nodeList.item(i);
if (Element.class.isAssignableFrom(child.getClass())) {
Element childElement = (Element) child;
String childTagName = getTagName(childElement);
if (childTagName.equals(tagName)) {
if (elements == null) {
elements = new ArrayList<Element>();
}
elements.add(childElement);
}
}
}
}
return elements;
}
public static List<Element> elements(Element element, Set<String> allowedTagNames) {
List<Element> elements = null;
NodeList nodeList = element.getChildNodes();
if (nodeList != null) {
for (int i = 0; i < nodeList.getLength(); i++) {
Node child = nodeList.item(i);
if (Element.class.isAssignableFrom(child.getClass())) {
Element childElement = (Element) child;
String childTagName = getTagName(childElement);
if (allowedTagNames.contains(childTagName)) {
if (elements == null) {
elements = new ArrayList<Element>();
}
elements.add(childElement);
}
}
}
}
return elements;
}
public static Element element(Element element, String tagName) {
Element childElement = null;
NodeList nodeList = element.getChildNodes();
for (int i = 0; ((i < nodeList.getLength()) && (childElement == null)); i++) {
Node child = nodeList.item(i);
if ((Element.class.isAssignableFrom(child.getClass())) && (getTagName((Element) child)).equals(tagName)) {
childElement = (Element) child;
}
}
return childElement;
}
public static List<Element> elements(Element element) {
List<Element> elements = null;
if (element!=null) {
NodeList nodeList = element.getChildNodes();
if ((nodeList != null) && (nodeList.getLength() > 0)) {
elements = new ArrayList<Element>();
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (node instanceof Element) {
elements.add((Element) node);
}
}
}
}
return elements;
}
public static List<Element> elements(Element father, String ns, String localName) {
List<Element> matchingElements = new ArrayList<Element>();
NodeList nl = father.getChildNodes();
for (int i=0;i<nl.getLength();i++) {
Node n = nl.item(i);
if (n instanceof Element && n.getLocalName() != null && n.getLocalName().equals(localName) && n.getNamespaceURI() != null && n.getNamespaceURI().equals(ns)) {
matchingElements.add((Element)n);
}
}
return matchingElements;
}
public static List<Element> elementsQName(Element element, Set<QName> allowedTagNames) {
List<Element> elements = null;
NodeList nodeList = element.getChildNodes();
if (nodeList != null) {
for (int i = 0; i < nodeList.getLength(); i++) {
Node child = nodeList.item(i);
if (Element.class.isAssignableFrom(child.getClass())) {
Element childElement = (Element) child;
QName childElementQName = new QName(childElement.getNamespaceURI(), childElement.getLocalName());
if (allowedTagNames.contains(childElementQName)) {
if (elements == null) {
elements = new ArrayList<Element>();
}
elements.add(childElement);
}
}
}
}
return elements;
}
public static Element element(Element element) {
Element onlyChild = null;
List elements = elements(element);
if (elements != null) {
onlyChild = (Element) elements.get(0);
}
return onlyChild;
}
public static String toString(Element element) {
if (element == null) {
return "null";
}
Source source = new DOMSource(element);
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
Result result = new StreamResult(printWriter);
try {
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.transform(source, result);
} catch (Exception e) {
log.severe("couldn't transform dom element into string representation");
return "<" + element.getTagName() + " ... >...</" + element.getTagName() + ">";
}
printWriter.close();
return stringWriter.toString();
}
public static String getContentText(Element element) {
StringBuffer buffer = new StringBuffer();
NodeList nodeList = element.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (node instanceof CharacterData) {
CharacterData characterData = (CharacterData) node;
buffer.append(characterData.getData());
}
}
return buffer.toString();
}
public static boolean isTextOnly(Element element) {
boolean isTextOnly = true;
NodeList nodeList = element.getChildNodes();
for (int i = 0; ((i < nodeList.getLength()) && (isTextOnly)); i++) {
if (Element.class.isAssignableFrom(nodeList.item(i).getClass())) {
isTextOnly = false;
}
}
return isTextOnly;
}
public static List<Attr> attributes(Element element) {
NamedNodeMap attributeMap = element.getAttributes();
if ((attributeMap == null) || (attributeMap.getLength() == 0)) {
return null;
}
List<Attr> attributes = new ArrayList<Attr>();
for (int i = 0; i < attributeMap.getLength(); i++) {
attributes.add((Attr) attributeMap.item(i));
}
return attributes;
}
public static List<Node> contents(Element element) {
NodeList nodeList = element.getChildNodes();
if ((nodeList == null) && (nodeList.getLength() != 0)) {
return null;
}
List<Node> contents = new ArrayList<Node>();
for (int i = 0; i < nodeList.getLength(); i++) {
contents.add((Node) nodeList.item(i));
}
return contents;
}
public static String getTagName(Element element) {
if (element == null) {
return null;
}
String localName = element.getLocalName();
if (localName != null) {
return localName;
}
return element.getTagName();
}
/**
* gets the attribute value and returns null in case the attribute is not
* present. The default dom behaviour is to return an empty string instead ?!?
*/
public static String attribute(Element element, String attributeName) {
if (element.hasAttribute(attributeName)) {
return element.getAttribute(attributeName);
} else {
return null;
}
}
public static Boolean booleanEquals(Element element, String attributeName, Boolean defaultValue) {
if (element.hasAttribute("auto-start")) {
String autoStartText = element.getAttribute("auto-start");
return XmlUtil.booleanEquals(autoStartText, defaultValue);
}
return defaultValue;
}
/**
* returns the boolean value for text values such as 'true', 'enabled',
* 'on', 'yes', 'false', 'disabled', 'off' & 'no'.
*
* If text is null, the defaultValue is returned.
* If text in {true, enabled, on, yes}, Boolean.TRUE is returned (case is ignored).
* If text in {false, disabled, off, no}, Boolean.FALSE is returned (case is ignored).
* If none of the above, null is returned.
*/
public static Boolean booleanEquals(String text, Boolean defaultValue) {
if (text==null) {
return defaultValue;
}
// if we have to check for value true
if ( ("true".equalsIgnoreCase(text))
|| ("enabled".equalsIgnoreCase(text))
|| ("on".equalsIgnoreCase(text))
|| ("yes".equalsIgnoreCase(text))
) {
return Boolean.TRUE;
}
if ( ("false".equalsIgnoreCase(text))
|| ("disabled".equalsIgnoreCase(text))
|| ("off".equalsIgnoreCase(text))
|| ("no".equalsIgnoreCase(text))
) {
return Boolean.FALSE;
}
return null;
}
public static List<String> parseList(Element element, String singularTagName) {
// a null value for text represents a wildcard
String text = XmlUtil.attribute(element, singularTagName + "s");
// so next we'll convert a '*' into the text null value, which indicates a
// wildcard
if ("*".equals(text)) {
text = null;
}
if (element.hasAttribute(singularTagName)) {
String eventText = element.getAttribute(singularTagName);
text = (text == null ? eventText : text + "," + eventText);
}
List<String> eventNames = parseCommaSeparatedList(text);
return eventNames;
}
/**
* parses comma or space separated list. A null return value means a wildcard.
*
* @return List of tokens or null if the commaSeparatedListText is null, '*',
* or empty
*/
public static List<String> parseCommaSeparatedList(String commaSeparatedListText) {
List<String> entries = null;
if (commaSeparatedListText != null) {
if (!"*".equals(commaSeparatedListText)) {
StringTokenizer tokenizer = new StringTokenizer(commaSeparatedListText, ", ");
while (tokenizer.hasMoreTokens()) {
if (entries == null) {
entries = new ArrayList<String>();
}
entries.add(tokenizer.nextToken());
}
}
}
return entries;
}
public static class NamespaceValue {
public String prefix;
public String localPart;
public NamespaceValue(String prefix, String localPart) {
this.prefix = prefix;
this.localPart = localPart;
}
}
public static NamespaceValue attributeNamespaceValue(Element element, String attributeName) {
NamespaceValue namespaceValue = null;
String text = attribute(element, attributeName);
if (text != null) {
int colonIndex = text.indexOf(':');
if (colonIndex == -1) {
namespaceValue = new NamespaceValue(null, text);
} else {
String prefix = text.substring(0, colonIndex);
String localPart = null;
if (text.length() > colonIndex + 1) {
localPart = text.substring(colonIndex + 1);
}
namespaceValue = new NamespaceValue(prefix, localPart);
}
}
return namespaceValue;
}
public static QName attributeQName(Element element, String attributeName) {
QName qname = null;
NamespaceValue namespaceValue = attributeNamespaceValue(element, attributeName);
String text = attribute(element, attributeName);
if (namespaceValue!=null) {
if (namespaceValue.prefix==null) {
qname = new QName(text);
} else {
String uri = element.lookupNamespaceURI(namespaceValue.prefix);
if (uri==null) {
throw new PvmException("unknown prefix in qname "+text);
} else if (namespaceValue.localPart==null) {
throw new PvmException("no local part in qname "+text);
} else {
qname = new QName(uri, namespaceValue.localPart, namespaceValue.prefix);
}
}
}
return qname;
}
public static QName getQNameFromString(Element element, String qnameAsString) {
if (qnameAsString == null || element == null) {
return null;
}
int colonIndex = qnameAsString.indexOf(":");
String prefix = qnameAsString.substring(0, colonIndex);
String localName = qnameAsString.substring(colonIndex + 1);
String ns = getNamespaceURI(element, prefix);
return new QName(ns, localName, prefix);
}
public static String getNamespaceURI(final org.w3c.dom.Node n, final String prefix) {
Node prefixDeclaration = n.getAttributes().getNamedItem("xmlns:" + prefix);
if (prefixDeclaration != null) {
// we have found the good NameSpace
return prefixDeclaration.getNodeValue();
}
// we have found the good NameSpace
// we look for the NameSpace in the parent Node
return getNamespaceURI(n.getParentNode(), prefix);
}
}