📄 xmlutil.java
字号:
/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the JBPM BPEL PUBLIC LICENSE AGREEMENT as
* published by JBoss Inc.; either version 1.0 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.
*/
package org.jbpm.bpel.xml.util;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.soap.Name;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPException;
import javax.xml.soap.Text;
import javax.xml.transform.Templates;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamSource;
import org.apache.commons.collections.IteratorUtils;
import org.apache.commons.collections.Predicate;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jaxen.JaxenException;
import org.jaxen.Navigator;
import org.jaxen.SimpleNamespaceContext;
import org.jaxen.UnsupportedAxisException;
import org.jaxen.XPath;
import org.jaxen.dom.DOMXPath;
import org.jaxen.dom.DocumentNavigator;
import org.jaxen.function.StringFunction;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import com.ibm.wsdl.util.xml.DOMUtils;
import org.jbpm.bpel.endpointref.EndpointReference;
import org.jbpm.bpel.xml.BpelConstants;
/**
* Utility methods for dealing with JAXP objects.
* @author Alejandro Gu韟ar
* @version $Revision: 1.5 $ $Date: 2007/01/22 17:27:03 $
*/
public class XmlUtil {
private static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
static final String DEFAULT_NAMESPACE_PREFIX = "defaultNS";
private static final Log log = LogFactory.getLog(XmlUtil.class);
private static final boolean traceEnabled = log.isTraceEnabled();
private static ThreadLocal documentBuilderLocal = new ThreadLocal() {
protected Object initialValue() {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setValidating(true);
factory.setCoalescing(true);
factory.setIgnoringElementContentWhitespace(true);
factory.setIgnoringComments(true);
try {
// Pick XML Schema as the schema language
factory.setAttribute(JAXP_SCHEMA_LANGUAGE, BpelConstants.NS_XML_SCHEMA);
}
catch (IllegalArgumentException e) {
log.fatal(
"JAXP implementation does not support XML Schema validation, "
+ "BPEL reader will not work properly", e);
throw new AssertionError(e);
}
try {
// Do full type checking
factory.setAttribute(
"http://apache.org/xml/features/validation/schema-full-checking",
Boolean.TRUE);
// Only do schema validation if a schema is specified as a namespace
factory.setAttribute(
"http://apache.org/xml/features/validation/dynamic", Boolean.TRUE);
}
catch (IllegalArgumentException e) {
log.warn("JAXP implementation is not Xerces, cannot enable dynamic schema validation, "
+ "XML documents without schema location will not parse.");
}
try {
DocumentBuilder documentBuilder = factory.newDocumentBuilder();
documentBuilder.setEntityResolver(new LocalEntityResolver());
return documentBuilder;
}
catch (ParserConfigurationException e) {
throw new RuntimeException("could not create document builder", e);
}
}
};
private static ThreadLocal transformerFactoryLocal = new ThreadLocal() {
protected Object initialValue() {
return TransformerFactory.newInstance();
}
};
private XmlUtil() {
// Suppress default constructor, ensuring non-instantiability
}
/**
* Gets the first child element of the given node with the specified local
* name and a <code>null</code> or empty namespace URI.
* @param parent the parent node to examine
* @param localName the local name of the desired child element
* @return the corresponding child element, or <code>null</code> if there is
* no match
*/
public static Element getElement(Node parent, String localName) {
return getElement(parent, null, localName);
}
/**
* Gets the first child element of the given SOAP element with the specified
* local name and a <code>null</code> or empty namespace URI. This overload
* is necessary as method {@link Node#getNextSibling()} does not behave as
* expected under some SAAJ implementations.
* @param parent the parent SOAP element to examine
* @param localName the local name of the desired child element
* @return the corresponding child element, or <code>null</code> if there is
* no match
*/
public static SOAPElement getElement(SOAPElement parent, String localName) {
return getElement(parent, null, localName);
}
/**
* Gets the first child element of the given node with the specified namespace
* URI and local name.
* @param parent the parent node to examine
* @param namespaceURI the namespace URI of the desired child element; if
* <code>null</code>, only elements with a <code>null</code> or
* empty namespace URI will be considered
* @param localName the local name of the desired child element
* @return the corresponding child element, or <code>null</code> if there is
* no match
*/
public static Element getElement(Node parent, String namespaceURI,
String localName) {
for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) {
if (QNameElementPredicate.evaluate(child, namespaceURI, localName))
return (Element) child;
}
return null;
}
/**
* Gets the first child element of the given SOAP element with the specified
* namespace URI and local name. This overload is necessary as method
* {@link Node#getNextSibling()} does not behave as expected under some SAAJ
* implementations.
* @param parent the parent node to examine
* @param namespaceURI the namespace URI of the desired child element; if
* <code>null</code>, only elements with a <code>null</code> or
* empty namespace URI will be considered
* @param localName the local name of the desired child element
* @return the corresponding child element, or <code>null</code> if there is
* no match
*/
public static SOAPElement getElement(SOAPElement parent, String namespaceURI,
String localName) {
Iterator childIt = parent.getChildElements();
while (childIt.hasNext()) {
javax.xml.soap.Node child = (javax.xml.soap.Node) childIt.next();
if (QNameElementPredicate.evaluate(child, namespaceURI, localName))
return (SOAPElement) child;
}
return null;
}
/**
* Gets the first child element of the given node.
* @param parent the parent node to examine
* @return the corresponding child element, or <code>null</code> if there is
* no match
*/
public static Element getElement(Node parent) {
for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) {
if (child.getNodeType() == Node.ELEMENT_NODE)
return (Element) child;
}
return null;
}
/**
* Gets the first child element of the given SOAP element.
* @param parent the parent SOAP element to examine
* @return the corresponding child element, or <code>null</code> if there is
* no match
*/
public static SOAPElement getElement(SOAPElement parent) {
Iterator childIt = parent.getChildElements();
while (childIt.hasNext()) {
Object child = childIt.next();
if (child instanceof SOAPElement)
return (SOAPElement) child;
}
return null;
}
/**
* Gets an iterator over the child elements of the given node with the
* specified namespace URI and any local name.
* @param parent the parent node to iterate
* @param namespaceURI the namespace URI of the desired child elements; if
* <code>null</code>, only elements with a <code>null</code> or
* empty namespace URI will be iterated
* @return an {@link Element} iterator, empty if there is no match
*/
public static Iterator getElements(Node parent, String namespaceURI) {
return IteratorUtils.filteredIterator(new NodeIterator(parent),
new NamespaceElementPredicate(namespaceURI));
}
/**
* Gets an iterator over the child elements of the given node with the
* specified namespace URI and local name.
* @param parent the parent node to iterate
* @param namespaceURI the namespace URI of the desired child elements; if
* <code>null</code>, only elements with a <code>null</code> or
* empty namespace URI will be iterated
* @param localName the local name of the desired child elements
* @return an {@link Element} iterator, empty if there is no match
*/
public static Iterator getElements(Node parent, String namespaceURI,
String localName) {
return IteratorUtils.filteredIterator(new NodeIterator(parent),
new QNameElementPredicate(namespaceURI, localName));
}
/**
* Gets an attribute value of the given element.
* @param ownerElem the element that owns the attribute
* @param attrName the name of the attribute to retrieve
* @return the attribute value as a string, or <code>null</code> if that
* attribute does not have a specified value
*/
public static String getAttribute(Element ownerElem, String attrName) {
Attr attribute = ownerElem.getAttributeNode(attrName);
return attribute != null ? attribute.getValue() : null;
}
/**
* Resolves a qualified name from a prefixed name appearing in the context of
* the given node.
* @param prefixedName a name that may contain a colon character
* @param contextNode the node to search for namespace declarations
* @return a qualified name whose fields are set as follows:
* <ul>
* <li><i>localPart</i> substring of the name after the first colon</li>
* <li><i>prefix</i> substring of the name before the first colon</li>
* <li><i>namespaceURI</i> namespace associated with the prefix
* above</li>
* </ul>
*/
public static QName getQName(String prefixedName, Node contextNode) {
String prefix;
String namespaceURI;
String localPart;
int index = prefixedName.indexOf(':');
if (index == -1) {
localPart = prefixedName;
prefix = "";
namespaceURI = "";
}
else {
localPart = prefixedName.substring(index + 1);
prefix = prefixedName.substring(0, index);
namespaceURI = getNamespaceURI(prefix, contextNode);
}
return new QName(namespaceURI, localPart, prefix);
}
public static String getStringValue(Object value) {
return DatatypeUtil.toString(value);
}
public static void setObjectValue(Node node, Object value) {
switch (node.getNodeType()) {
case Node.ELEMENT_NODE:
setObjectValue((Element) node, value);
break;
case Node.DOCUMENT_NODE:
setObjectValue(((Document) node).getDocumentElement(), value);
break;
default:
// replace content
node.setNodeValue(getStringValue(value));
}
}
public static void setObjectValue(Element elem, Object value) {
if (value instanceof Node) {
if (value instanceof SOAPElement) {
// replace element
copy(elem, (SOAPElement) value);
}
else if (value instanceof Element) {
// replace element
copy(elem, (Element) value);
}
else if (value instanceof Document) {
// replace element
copy(elem, ((Document) value).getDocumentElement());
}
else {
// replace content
setStringValue(elem, ((Node) value).getNodeValue());
}
}
else if (value instanceof EndpointReference) {
// replace element
((EndpointReference) value).writeServiceRef(elem);
}
else {
// replace content
setStringValue(elem, StringFunction.evaluate(value,
DocumentNavigator.getInstance()));
}
}
public static void setStringValue(Element elem, String value) {
// remove xsi:nil
elem.removeAttributeNS(BpelConstants.NS_XML_SCHEMA_INSTANCE,
BpelConstants.ATTR_NIL);
// save first child
Node firstChild = elem.getFirstChild();
// if first child is text, reuse it
if (firstChild instanceof org.w3c.dom.Text) {
firstChild.setNodeValue(value);
}
// otherwise, just create new text
else {
firstChild = elem.getOwnerDocument().createTextNode(value);
}
// remove all children
removeChildNodes(elem);
// append text
elem.appendChild(firstChild);
}
static final String QUALIFIED_VALUE_PREFIX = "valueNS";
public static void setQNameValue(Element elem, QName value) {
String namespace = value.getNamespaceURI();
String prefixedValue;
if (namespace.length() > 0) {
String prefix = XmlUtil.getPrefix(namespace, elem);
if (prefix == null) {
prefix = generatePrefix(elem, QUALIFIED_VALUE_PREFIX);
addNamespaceDeclaration(elem, namespace, prefix);
}
prefixedValue = prefix + ':' + value.getLocalPart();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -