import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
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;
import org.xml.sax.SAXException;
/**
* W3CDom工具类
*/
public abstract class W3CDomUtil{
private static final Map< File, Document > DOC_CACHE = new HashMap< File, Document >( );
private static final Map< File, Long > DOC_LASTMODIFIEDS = new HashMap< File, Long >( );
private static final Map< URL, Validator > XSD_CACHE = new HashMap< URL, Validator >( );
/**
* 创建一个Document对象
* @return 一个新的Document对象
*/
public static Document newDocument( final String root ){
return newDocument( root, null, false );
}
public static Document newDocument( final String root, final String nsURI ){
return newDocument( root, nsURI, false );
}
public static Document newDocument( final String root, final boolean ignoreWhitespace ){
return newDocument( root, null, ignoreWhitespace );
}
public static Document newDocument( final String root, final String nsURI, final boolean ignoreWhitespace ){
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setIgnoringElementContentWhitespace( ignoreWhitespace );
try{
final DocumentBuilder db = factory.newDocumentBuilder();
return db.getDOMImplementation().createDocument( nsURI, root, null );
} catch( final ParserConfigurationException ex ){
throw new IllegalArgumentException( ex );
}
}
public static Document loadDocument( final String xml, final String charSet ){
return loadDocument( xml, null, false, charSet );
}
public static Document loadDocument( final String xml, final URL xsdURL, final String charSet ){
return loadDocument( xml, xsdURL, false, charSet );
}
/**
* 根据xml字符串读取document
*/
public static Document loadDocument( final String xml, final boolean ignoreWhitespace, final String charSet ){
return loadDocument( xml, null, ignoreWhitespace, charSet );
}
public static Document loadDocument( final String xml, final URL xsdURL, final boolean ignoreWhitespace, final String charSet ){
String encoding = "UTF-8";
if( StringUtil.isNotNullNotEmpty( charSet ) ){
encoding = charSet;
}
try{
return loadDocument( new ByteArrayInputStream( xml.getBytes( encoding ) ), xsdURL, ignoreWhitespace );
} catch( final UnsupportedEncodingException ex ){
throw new IllegalArgumentException( ex );
}
}
public static Document loadDocument( final String path ){
return loadDocument( path, null, false );
}
public static Document loadDocument( final String path, final URL xsdURL ){
return loadDocument( path, xsdURL, false );
}
/**
* 从指定文件路径读取Document
* @param path 指定文件的绝对路径
* @param ignoreWhitespace 是否忽略空白节点
*/
public static Document loadDocument( final String path, final boolean ignoreWhitespace ){
return loadDocument( path, null, ignoreWhitespace );
}
public static Document loadDocument( final String path, final URL xsdURL, final boolean ignoreWhitespace ){
return loadDocument( new File( path ), xsdURL, ignoreWhitespace );
}
public static Document loadDocument( final File file ){
return loadDocument( file, null, false );
}
public static Document loadDocument( final File file, final URL xsdURL ){
return loadDocument( file, xsdURL, false );
}
/**
* 从指定文件读取Document
* @param file 指定文件
* @param ignoreWhitespace 是否忽略空白节点
*/
public static Document loadDocument( final File file, final boolean ignoreWhitespace ){
return loadDocument( file, null, ignoreWhitespace );
}
public static Document loadDocument( final File file, final URL xsdURL, final boolean ignoreWhitespace ){
if( file == null || !file.exists( ) || file.isDirectory( ) ){
throw new IllegalArgumentException( "Can NOT get the xml file: " + file.getAbsolutePath( ) );
}
Document document = DOC_CACHE.get( file );
if( document == null || DOC_LASTMODIFIEDS.get( file ) < file.lastModified( ) ){
try{
DOC_CACHE.put( file, document = loadDocument( new FileInputStream( file ), xsdURL, ignoreWhitespace ) );
DOC_LASTMODIFIEDS.put( file, file.lastModified( ) );
} catch( final FileNotFoundException ex ){
throw new IllegalArgumentException( ex );
}
}
return document;
}
public static Document loadDocument( final InputStream is ){
return loadDocument( is, null, false );
}
public static Document loadDocument( final InputStream is, final URL xsdURL ){
return loadDocument( is, xsdURL, false );
}
/**
* 从输入流读取Document
* @param is 输入流
* @param ignoreWhitespace 是否忽略空白节点
*/
public static Document loadDocument( final InputStream is, final boolean ignoreWhitespace ){
return loadDocument( is, null, ignoreWhitespace );
}
public static Document loadDocument( final InputStream is, final URL xsdURL, final boolean ignoreWhitespace ){
if( null == is ){
throw new IllegalArgumentException( "Xml InputStream not availible." );
}
final Validator validator = getValidator( xsdURL );
final InputStream buffer = new UnclosableBufferedInputStream( is );
if( null != validator ){
try{
buffer.mark( 0 );
validator.validate( new StreamSource( buffer ) );
buffer.reset( );
}
catch( final IOException ex ){
throw new IllegalArgumentException( ex );
}
catch( final SAXException ex ){
throw new IllegalArgumentException( ex );
}
}
try{
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance( );
factory.setIgnoringElementContentWhitespace( ignoreWhitespace );
return factory.newDocumentBuilder( ).parse( buffer );
} catch( final IOException ex ){
throw new IllegalArgumentException( ex );
} catch( final SAXException ex ){
throw new IllegalArgumentException( ex );
} catch( final ParserConfigurationException ex ){
throw new IllegalArgumentException( ex );
} finally{
try{ is.close( ); }
catch( final IOException ignored ){ }
}
}
/**
* 保存Document到指定的文件路径
* @throws TransformerException 文档向目标文件传输拷贝失败时抛出该异常
* @throws IOException 文件创建失败时抛出该异常
*/
public static void saveDocument( final String filePath, final Document doc ){
saveDocument( filePath, null, doc );
}
public static void saveDocument( final String filePath, final URL xsdURL, final Document doc ){
Assert.isNotNull( filePath );
saveDocument( new File( filePath ), xsdURL, doc );
}
public static void saveDocument( final File file, final Document doc ){
saveDocument( file, null, doc );
}
/**
* 保存Document到指定的文件
* @throws TransformerException 文档向目标文件传输拷贝失败时抛出该异常
* @throws IOException 文件创建失败时抛出该异常
*/
public static void saveDocument( final File file, final URL xsdURL, final Document doc ){
Assert.isNotNull( file );
try{
if( !file.exists( ) ){
file.createNewFile( );
}
saveDocument( new FileOutputStream( file ), xsdURL, doc );
} catch( final FileNotFoundException ex ){
throw new IllegalArgumentException( ex );
} catch( final IOException ex ){
throw new IllegalArgumentException( ex );
}
}
public static void saveDocument( final OutputStream os, final Document doc ){
saveDocument( os, null, doc );
}
public static void saveDocument( final OutputStream os, final URL xsdURL, final Document doc ){
if( null == os ){
throw new IllegalArgumentException( "Xml OutputStream not availible." );
}
final Validator validator = getValidator( xsdURL );
final Source source = new DOMSource( doc );
if( null != validator ){
try{
validator.validate( source );
} catch( final IOException ex ){
throw new IllegalArgumentException( ex );
} catch( final SAXException ex ){
throw new IllegalArgumentException( ex );
}
}
try{
final TransformerFactory transformerFactory = TransformerFactory.newInstance( );
transformerFactory.setAttribute( "indent-number", 4 );
final Transformer transformer = transformerFactory.newTransformer( );
transformer.setOutputProperty( OutputKeys.VERSION, "1.0" );
transformer.setOutputProperty( OutputKeys.ENCODING, "utf-8" );
transformer.setOutputProperty( OutputKeys.INDENT, "yes" );
transformer.setOutputProperty( "{http://xml.apache.org/xslt}indent-amount", "4" );
transformer.transform( source, new StreamResult( new OutputStreamWriter( os, "utf-8" ) ) );
} catch( final TransformerConfigurationException ex ){
throw new IllegalArgumentException( ex );
} catch( final TransformerException ex ){
throw new IllegalArgumentException( ex );
} catch( final UnsupportedEncodingException ex ){
throw new IllegalArgumentException( ex );
} finally{
try{
os.flush( );
os.close( );
} catch( final IOException ignored ){ }
}
}
/**
* 合并多个文档至一个
*/
public static Document combineDocument(Document ... docs) throws TransformerException {
Document res = null;
for(Document doc : docs) {
if(res == null) {
res = doc;
} else if(doc != null) {
Element ele = doc.getDocumentElement();
NodeList list = ele.getChildNodes();
for(int i = 0, size = list.getLength(); i < size; i++) {
copyNodes(list.item(i), res.getDocumentElement());
}
}
}
return res;
}
/**
* 获取节点所在的文档对象
*/
public static Document getOwnerDocument(Node node) {
return node instanceof Document ? (Document) node : node.getOwnerDocument();
}
/**
* 根据xpath表达式和指定起始节点搜索目标节点,并获取目标节点的content text,
* 因为目标节点可能有多个,所以返回为List,并且content text都已清除左右的空
* 白文本内容
* @param express xpath表达式
* @param node 指定起始节点
* @throws XPathExpressionException 执行失败抛出该异常
*/
public static List<String> getTextTrim(Node node, String express) throws XPathExpressionException {
Assert.isNotNull(node, "Node can not be null");
Assert.isNotNull(express, "Express can not be null");
NodeList list = selectNodes(node, express);
if (list != null && list.getLength() > 0) {
List<String> resList = new ArrayList<String>(list.getLength());
for (int i = 0, size = list.getLength(); i < size; i++) {
Node resNode = list.item(i);
String text = getText(resNode);
resList.add(text == null ? null : text.trim());
}
return resList;
}
return Collections.emptyList();
}
/**
* 根据xpath表达式和指定起始节点搜索目标节点,并获取目标节点的content text,
* 只获取搜到的第一个节点的content text
* @param express xpath表达式
* @param node 指定起始节点
* @throws XPathExpressionException 执行失败抛出该异常
*/
public static String getSingleText(Node node, String express) throws XPathExpressionException {
Assert.isNotNull(node, "Node can not be null");
Assert.isNotNull(express, "Express can not be null");
Node nsObj = selectSingleNode(node, express);
if (nsObj != null) {
return getText(nsObj);
}
return null;
}
/**
* 根据xpath表达式和指定起始节点搜索目标节点,并获取目标节点的content text,
* 只获取搜到的第一个节点的content text,并且content text已清除左右的空
* 白文本内容
* @param express xpath表达式
* @param node 指定起始节点
* @throws XPathExpressionException 执行失败抛出该异常
*/
public static String getSingleTextTrim(Node node, String express) throws XPathExpressionException {
String res = getSingleText(node, express);
if (res != null) {
return res.trim();
}
return res;
}
/**
* 将指定节点(包括子节点)克隆拷贝到目标节点下
* @param source 指定源节点
* @param target 目标节点
* @throws TransformerException 执行失败抛出该异常
*/
public static void copyNodes(Node source, Node target) throws TransformerException {
Assert.isNotNull(source, "source node can not be null");
Assert.isNotNull(target, "target can not be null");
TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer transformer = transFactory.newTransformer();
DOMSource domSource = new DOMSource();
domSource.setNode(source);
DOMResult domResult = new DOMResult();
domResult.setNode(target);
transformer.transform(domSource, domResult);
}
/**
* 将node的XML字符串输出到输出流
* @throws TransformerException 执行失败抛出该异常
*/
public static void output(Node node, OutputStream os) throws TransformerException {
TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer transformer = transFactory.newTransformer();
transformer.setOutputProperty("encoding", "UTF-8");
transformer.setOutputProperty("indent", "yes");
DOMSource source = new DOMSource();
source.setNode(node);
StreamResult result = new StreamResult();
result.setOutputStream(os);
transformer.transform(source, result);
}
/**
* 查找节点,并返回第一个符合条件节点
* @throws XPathExpressionException 执行失败抛出该异常
*/
public static Node selectSingleNode(Object source, String express) throws XPathExpressionException {
Node result = null;
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
result = (Node) xpath.evaluate(express, source, XPathConstants.NODE);
return result;
}
/**
* 查找节点,返回符合条件的节点集
* @throws XPathExpressionException 执行失败抛出该异常
*/
public static NodeList selectNodes(Object source, String express) throws XPathExpressionException {
NodeList result = null;
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
result = (NodeList) xpath.evaluate(express, source, XPathConstants.NODESET);
return result;
}
/**
* 查找节点,并返回第一个符合条件节点,带命名空间的查找
* @throws XPathExpressionException 执行失败抛出该异常
*/
public static Node selectSingleNodeWithNamespace(Object source, String express, String prefix, String namespace) throws XPathExpressionException {
Node result = null;
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
xpath.setNamespaceContext(new MENamespaceContext(namespace, prefix));
result = (Node) xpath.evaluate(express, source, XPathConstants.NODE);
return result;
}
/**
* 查找节点,返回符合条件的节点集,带命名空间的查找
* @throws XPathExpressionException 执行失败抛出该异常
*/
public static NodeList selectNodesWithNamespace(Object source, String express, String prefix, String namespace) throws XPathExpressionException {
NodeList result = null;
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
xpath.setNamespaceContext(new MENamespaceContext(namespace, prefix));
result = (NodeList) xpath.evaluate(express, source, XPathConstants.NODESET);
return result;
}
/**
* 获取某节点的指定名称的子节点,仅返回第一个匹配的
*/
public static Node getChildNode(Node node, String name) {
Assert.isNotNull(node, "Node can not be null");
NodeList nodes = node.getChildNodes();
Node child = null;
for (int i = 0; i < nodes.getLength(); i++) {
child = nodes.item(i);
if(child.getNodeName().equals(name)) {
return child;
}
}
return null;
}
/**
* 获取某节点的指定名称的子节点,返回所有匹配的节点的List结合
*/
public static List<Node> getChildNodes(Node node, String name) {
Assert.isNotNull(node, "Node can not be null");
NodeList nodes = node.getChildNodes();
List<Node> list = new ArrayList<Node>();
Node child = null;
for (int i = 0; i < nodes.getLength(); i++) {
child = nodes.item(i);
if(child.getNodeName().equals(name)) {
list.add(child);
}
}
return list;
}
/**
* 强制获取某节点下指定名称的子节点,即如果子节点不存在,则创建一个新的
* 名称匹配的子节点插入并返回
*/
public static Node getNodeNullChildNode(Node node, String name) {
Node childNode = getChildNode(node, name);
if(childNode == null) {
childNode = appendChildNode(node, name);
}
return childNode;
}
/**
* 获取某个节点的CDATA内容
*/
public static String getNodeCDATA(Node node) {
Assert.isNotNull(node, "Node can not be null");
NodeList list = node.getChildNodes();
for(int i = 0, size = list.getLength(); i < size; i++) {
if(list.item(i).getNodeType() == Node.CDATA_SECTION_NODE) {
return list.item(i).getNodeValue();
}
}
return null;
}
/**
* 获取某个节点的CDATA内容,如果为空,返回空字符串
*/
public static String getAbsoluteNodeCDATA(Node node) {
String res = getNodeCDATA(node);
if(res == null) {
res = "";
}
return res;
}
/**
* 获取某个节点的content text
*/
public static String getText(Node node) {
Assert.isNotNull(node, "Node can not be null");
NodeList list = node.getChildNodes();
for(int i = 0, size = list.getLength(); i < size; i++) {
if(list.item(i).getNodeType() == Node.TEXT_NODE) {
return list.item(i).getNodeValue();
}
}
return null;
}
/**
* 获取某个节点的content text,如果为空,返回空字符串
*/
public static String getNotNullText(Node node) {
String res = getText(node);
if(res == null) {
res = "";
}
return res;
}
/**
* 获取某个节点的content text并删除左右的空白字符,如果为空,返回空字符串
*/
public static String getNotNullTextTrim(Node node) {
String text = getText(node);
if(text == null) {
text = "";
}
return text.trim();
}
/**
* 获取某个节点的content text并删除左右的空白字符,如果为空,返回空
*/
public static String getTextTrim(Node node) {
String text = getText(node);
return text == null ? null : text.trim();
}
/**
* 获取某个节点的指定属性的值
*/
public static String getAttributeValue(Node node, String attrName) {
Assert.isNotNull(attrName, "Attribute name can not be null");
Assert.isNotNull(node, "Node can not be null");
NamedNodeMap list = node.getAttributes();
Node attrNode = list.getNamedItem(attrName);
if(attrNode == null) {
return null;
}
return attrNode.getNodeValue();
}
/**
* 获取某个节点的指定属性的值,如果为空,返回空字符串
*/
public static String getNotNullAttributeValue(Node node, String attrName) {
String value = getAttributeValue(node, attrName);
if(value == null) {
value = "";
}
return value;
}
/**
* 获取某个节点的指定属性的值并删除左右的空白
*/
public static String getAttributeValueTrim(Node node, String attrName) {
String value = getAttributeValue(node, attrName);
return value == null ? null : value.trim();
}
/**
* 获取指定节点的第一个指定属性名称的属性节点,如果不存在,创建一个
*/
public static Node getAbsoluteFirstSpecifyAttributeNode(Node node, String attrName) {
Assert.isNotNull(attrName, "Attribute name can not be null");
Assert.isNotNull(node, "Node can not be null");
NamedNodeMap list = node.getAttributes();
for(int i = 0, size = list.getLength(); i < size; i++) {
if(list.item(i).getNodeName().equals(attrName)) {
return list.item(i);
}
}
return W3CDomUtil.appendAttributeNode(node, attrName);
}
/**
* 获取指定节点的第一个属性节点
*/
public static Node getFirstAttributeNode(Node node) {
Assert.isNotNull(node, "Node can not be null");
NamedNodeMap list = node.getAttributes();
if(list.getLength() == 0) {
return null;
} else {
return list.item(0);
}
}
/**
* 获取某个节点的指定名称的子节点的content text
*/
public static String getChildNodeText(Node node, String name) {
Node child = getChildNode(node, name);
if(child == null) {
return null;
}
return getText(child);
}
/**
* 获取某个节点的指定名称的子节点的content text,如果为空则返回空字符串
*/
public static String getAbsoluteChildNodeText(Node node, String name) {
String res = getChildNodeText(node, name);
if(res == null) {
res = "";
}
return res;
}
/**
* 更新某个节点的content text
* @param text 更新的内容
* @param node 指定的节点
* @param trimText 是否清除左右空白文本
*/
public static void updateNodeText(Node node, String text, boolean trimText) {
Assert.isNotNull(node, "Node can not be null");
NodeList list = node.getChildNodes();
for(int i = 0, size = list.getLength(); i < size; i++) {
if(list.item(i).getNodeType() == Node.TEXT_NODE) {
String oldText = list.item(i).getNodeValue();
oldText = (oldText != null && trimText) ? oldText.trim() : oldText;
if(oldText == null || !oldText.equals(text)) {
list.item(i).setNodeValue(text == null ? "" : text);
}
return;
}
}
Node newTextNode = appendTextNode(node);
newTextNode.setNodeValue(text == null ? "" : text);
}
/**
* 更新某个节点的指定子节点的content text,如果子节点不存在,则创建一个插入再更新
* @param childName 指定的子节点名称
* @param text 更新的内容
* @param parent 指定的节点
* @param isFirst 是否插入到最前
* @param trimText 是否清除左右空白文本
* @return 被更新的子节点
*/
public static Node updateChildNodeTextAbsolute(Node parent, String childName, String text, boolean isFirst, boolean trimText) {
Node childNode = getChildNode(parent, childName);
if(childNode == null) {
if(isFirst) {
childNode = appendChildNodeAtFirst(parent, childName);
} else {
childNode = appendChildNode(parent, childName);
}
}
String oldText = getText(childNode);
oldText = oldText == null ? "" : oldText;
oldText = trimText ? oldText.trim() : oldText;
if(!oldText.equals(text)) {
updateNodeText(childNode, text, trimText);
}
return childNode;
}
/**
* 更新某个节点的CDATA
* @param cdata 更新的CDATA
* @param node 指定的节点
* @param trimText 是否清除左右空白文本
*/
public static void updateNodeCDATA(Node node, String cdata, boolean trimText) {
Assert.isNotNull(node, "Node can not be null");
NodeList list = node.getChildNodes();
for(int i = 0, size = list.getLength(); i < size; i++) {
if(list.item(i).getNodeType() == Node.CDATA_SECTION_NODE) {
String oldText = list.item(i).getNodeValue();
oldText = (oldText != null && trimText) ? oldText.trim() : oldText;
if(oldText == null || !oldText.equals(cdata)) {
list.item(i).setNodeValue(cdata == null ? "" : cdata);
}
return;
}
}
Node newTextNode = appendCDATANode(node);
newTextNode.setNodeValue(cdata == null ? "" : cdata);
}
/**
* 更新某个节点的指定子节点的CDATA,如果子节点不存在,则创建一个插入再更新
* @param childName 指定的子节点名称
* @param cdata 更新的CDATA
* @param parent 指定的节点
* @param trimText 是否清除左右空白文本
* @return 被更新的子节点
*/
public static Node updateChildNodeCDATAAbsolute(Node parent, String childName, String cdata, boolean trimText) {
Node childNode = getChildNode(parent, childName);
if(childNode == null) {
childNode = appendChildNodeAtFirst(parent, childName);
Node attrNode = appendNSAttrNode(childNode, "xml", "lang");
attrNode.setNodeValue("zh-cn");
}
String oldCDATA = getNodeCDATA(childNode);
oldCDATA = oldCDATA == null ? "" : oldCDATA;
oldCDATA = trimText ? oldCDATA.trim() : oldCDATA;
if(!oldCDATA.equals(cdata)) {
updateNodeCDATA(childNode, cdata, trimText);
}
return childNode;
}
/**
* 移除节点的后续空白节点
*/
private static void removeNextSiblingWhitespace(Node node) {
Assert.isNotNull(node, "Node can not be null");
Node parent = node.getParentNode();
Node txtNode = node.getNextSibling();
if (txtNode != null && txtNode.getNodeType() == Node.TEXT_NODE
&& StringUtil.isNullOrEmpty(txtNode.getNodeValue())) {
parent.removeChild(txtNode);
}
}
/**
* 清除指定的节点
*/
public static void removeChild(Node node) {
Assert.isNotNull(node, "Node can not be null");
Node parent = node.getParentNode();
if(parent != null) {
removeNextSiblingWhitespace(node);
parent.removeChild(node);
}
}
/**
* 删除父节点下指定名称集合中的子节点
*/
public static void removeChildren(Node parent, String[] names) {
Assert.isNotNull(parent, "Parent can not be null");
if(names == null || names.length < 1) {
return;
}
NodeList list = parent.getChildNodes();
for(int i = 0, size = list.getLength(); i < size; i++) {
for(int j = 0; j < names.length; j++) {
if (list.item(i) != null // because in the loop we may remove some children ,so here must do a check
&& list.item(i).getNodeName().equals(names[j])) {
removeNextSiblingWhitespace(list.item(i));
parent.removeChild(list.item(i));
break;
}
}
}
parent.normalize();
}
/**
* 删除指定节点的所有属性
*/
public static void removeAllAttributes(Node node) {
Assert.isNotNull(node, "Node can not be null");
NamedNodeMap list = node.getAttributes();
for(int i = 0, size = list.getLength(); i < size; i++) {
list.removeNamedItem(list.item(i).getNodeName());
}
}
/**
* 创建插入指定名称的子节点到父节点下子节点集的最前
*/
public static Node appendChildNodeAtFirst(Node parent, String name) {
Assert.isNotNull(name, "Name can not be null");
Assert.isNotNull(parent, "Parent can not be null");
Node node = getOwnerDocument(parent).createElement(name);
NodeList list = parent.getChildNodes();
if(list.getLength() > 0) {
parent.insertBefore(node, list.item(0));
} else {
parent.insertBefore(node, null);
}
return node;
}
/**
* 创建插入指定名称的子节点到父节点下子节点集的某个指定子节点之前
*/
public static Node appendChildNodeBeforeSpecifyChildNode(Node parent, Node child, String name) {
Assert.isNotNull(name, "Name can not be null");
Assert.isNotNull(parent, "Parent can not be null");
Node node = getOwnerDocument(parent).createElement(name);
parent.insertBefore(node, child);
return node;
}
/**
* 创建插入指定名称的子节点到父节点下子节点集的某个指定子节点之后,若找不到指定子节点,插入到最后
*/
public static Node appendChildNodeAfterSpecifyChildNode(Node parent, Node child, String name) {
Assert.isNotNull(name, "Name can not be null");
Assert.isNotNull(parent, "Parent can not be null");
Node node = getOwnerDocument(parent).createElement(name);
NodeList list = parent.getChildNodes();
boolean finish = false;
for(int i = 0, size = list.getLength(); i < size; i++) {
if(list.item(i).equals(child) && (i + 1) < size) {
parent.insertBefore(node, list.item(i + 1));
finish = true;
break;
}
}
if(!finish) {
parent.appendChild(node);
}
return node;
}
/**
* 创建插入指定名称的子节点到父节点下,默认在父节点下子节点集的最后
*/
public static Node appendChildNode(Node parent, String name) {
Assert.isNotNull(name, "Name can not be null");
Assert.isNotNull(parent, "Parent can not be null");
Node node = getOwnerDocument(parent).createElement(name);
parent.appendChild(node);
return node;
}
/**
* 创建插入指定名称的子节点到父节点下,默认在父节点下子节点集的最后,并设置该节点的text内容
*/
public static Node appendChildNodeWithText(Node parent, String name, String text) {
Node node = appendChildNode(parent, name);
node.setTextContent(text);
return node;
}
/**
* 向父节点插入一个文本节点
*/
public static Node appendTextNode(Node parent) {
Assert.isNotNull(parent, "Parent can not be null");
Node node = getOwnerDocument(parent).createTextNode("");
parent.appendChild(node);
return node;
}
/**
* 向父节点插入一个CDATA节点
*/
public static Node appendCDATANode(Node parent) {
Assert.isNotNull(parent, "Parent can not be null");
Node node = getOwnerDocument(parent).createCDATASection("");
parent.appendChild(node);
return node;
}
/**
* 对指定节点插入属性
* @param parent 指定节点
* @param name 属性名
* @return 属性节点
*/
public static Node appendAttributeNode(Node parent, String name) {
Assert.isNotNull(parent, "Parent can not be null");
Node node = getOwnerDocument(parent).createAttribute(name);
parent.getAttributes().setNamedItem(node);
return node;
}
/**
* 对指定节点插入属性,带命名空间
* @param parent 指定节点
* @param uri 命名空间
* @param name 属性名
* @return 属性节点
*/
public static Node appendNSAttrNode(Node parent, String uri, String name) {
Assert.isNotNull(parent, "Parent can not be null");
Node node = getOwnerDocument(parent).createAttributeNS(uri, name);
parent.getAttributes().setNamedItemNS(node);
return node;
}
/**
* 判断指定父节点是否存在指定名称的子节点(直接父子关系)
*/
public static boolean hasChildNode(Node parent, String childNodeName) {
Assert.isNotNull(parent, "Parent can not be null");
Assert.isNotNull(childNodeName, "ChildNode name can not be null");
Node child = parent.getFirstChild();
for (; child != null; child = child.getNextSibling()) {
if (child.getNodeType() == Node.ELEMENT_NODE && childNodeName.equals(child.getNodeName())) {
return true;
}
}
return false;
}
/**
* 判断指定父节点是否存在指定名称和文本内容的子节点(直接父子关系)
*/
public static boolean hasChildNodeText(Node parent, String childNodeName, String childNodeText) {
Assert.isNotNull(parent, "Parent can not be null");
Assert.isNotNull(childNodeName, "ChildNode name can not be null");
Node child = parent.getFirstChild();
for (; child != null; child = child.getNextSibling()) {
if (child.getNodeType() == Node.ELEMENT_NODE && childNodeName.equals(child.getNodeName())
&& childNodeText.equals(getText(child))) {
return true;
}
}
return false;
}
public static Validator getValidator( final URL xsdURL ){
Validator validator = null;
if( null != xsdURL ){
validator = XSD_CACHE.get( xsdURL );
if( null == validator && null != xsdURL ){
InputStream stream = null;
try{
final SchemaFactory factory = SchemaFactory.newInstance( javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI );
stream = xsdURL.openStream( );
final Source schemaSource = new StreamSource( stream );
final Schema schema = factory.newSchema( schemaSource );
XSD_CACHE.put( xsdURL, validator = schema.newValidator( ) );
} catch( final IOException ex ){
throw new IllegalArgumentException( ex );
} catch( final SAXException ex ){
throw new IllegalArgumentException( ex );
} finally{
try{
if( null != stream ) {
stream.close( );
}
} catch ( final IOException ignored ) { }
}
}
}
return validator;
}
protected static class MENamespaceContext implements NamespaceContext {
private String namespace;
private String prefix;
public String getNamespaceURI(String pfx) {
if (prefix.equals(pfx)) {
return namespace;
}
return "";
}
public String getPrefix(String arg0) {
return null;
}
public Iterator getPrefixes(String arg0) {
return null;
}
public MENamespaceContext(String namespace, String prefix) {
this.namespace = namespace;
this.prefix = prefix;
}
}
private static class UnclosableBufferedInputStream extends BufferedInputStream{
public UnclosableBufferedInputStream( final InputStream in ){
super( in );
}
public void close( ) throws IOException{ }
}
}