Java tutorial
/* * JEF - Copyright 2009-2010 Jiyi (mr.jiyi@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jef.tools; import java.io.BufferedReader; import java.io.File; import java.io.FilterReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PushbackInputStream; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.Array; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.NoSuchElementException; import javax.management.ReflectionException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.apache.commons.lang.StringEscapeUtils; import org.apache.html.dom.HTMLDocumentImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Attr; import org.w3c.dom.CDATASection; import org.w3c.dom.Comment; import org.w3c.dom.Document; import org.w3c.dom.DocumentFragment; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.Text; import org.w3c.dom.html.HTMLDocument; import org.xml.sax.EntityResolver; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import com.alibaba.fastjson.JSONObject; import jef.common.log.LogUtil; import jef.tools.io.Charsets; import jef.tools.reflect.BeanWrapper; import jef.tools.reflect.BeanWrapperImpl; import jef.tools.reflect.Property; import jef.tools.reflect.UnsafeUtils; /** * JAXP?XML??? * * * <b>??xercesImpl</b> * * <pre> * ?xerces?? * xerces apache? * ?xercesImpl 2.6.x2.11.x??? 2.7.1~2.9.1 * 2.7.1???cybernekoHTML??2.6.2? * 2.10.0org.w3c.dom.ElementTraversalJDK 6??xml-api * weblogic??? * 2.9.1 * </pre> * * @author jiyi * */ public class XMLUtils { private static final Logger log = LoggerFactory.getLogger("XMLUtils"); /** * DocumentBuilderFactory<br> * ?DocumentBuilderFactory0.3ms?? */ private static DocumentBuilderFactory domFactoryTT; private static DocumentBuilderFactory domFactoryTF; private static DocumentBuilderFactory domFactoryFT; private static DocumentBuilderFactory domFactoryFF; /** * ?????? */ static { try { Class.forName("org.apache.xerces.xni.XMLDocumentHandler"); try { Class<?> cParser = Class.forName("org.cyberneko.html.parsers.DOMFragmentParser"); if (cParser != null) { parser = (jef.tools.IDOMFragmentParser) cParser.newInstance(); } } catch (Exception e) { // common-net??HTML? LogUtil.warn( "The EF-HTML parser engine not found, HTMLParser feature will be disabled. Import easyframe 'common-misc' library to the classpath to activate this feature."); } } catch (Exception e) { // xerces??HTML? LogUtil.warn( "The Apache xerces implemention not avaliable, HTMLParser feature will be disabled. you must import library 'xercesImpl'(version >= 2.7.1) into classpath."); } try { domFactoryTT = initFactory(true, true); domFactoryTF = initFactory(true, false); domFactoryFT = initFactory(false, true); domFactoryFF = initFactory(false, false); } catch (Exception e) { log.error("FATAL: Error in init DocumentBuilderFactory. XML Parser will not work!", e); } } /* * ? * * @param ignorComments * * @param namespaceAware ?? * * @return DocumentBuilderFactoy */ private static DocumentBuilderFactory initFactory(boolean ignorComments, boolean namespaceAware) { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setIgnoringElementContentWhitespace(true); dbf.setValidating(false); // DTD dbf.setIgnoringComments(ignorComments); dbf.setNamespaceAware(namespaceAware); // dbf.setCoalescing(true);//CDATA // ?Text??? try { // dbf.setFeature("http://xml.org/sax/features/namespaces", false); // dbf.setFeature("http://xml.org/sax/features/validation", false); dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false); dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); } catch (ParserConfigurationException e) { log.warn( "Your xerces implemention is too old to support 'load-dtd-grammar' and 'load-external-dtd' feature. Please upgrade xercesImpl.jar to 2.6.2 or above."); } catch (AbstractMethodError e) { log.warn( "Your xerces implemention is too old to support 'load-dtd-grammar' and 'load-external-dtd' feature. Please upgrade xercesImpl.jar to 2.6.2 or above."); } try { dbf.setAttribute("http://xml.org/sax/features/external-general-entities", false); } catch (IllegalArgumentException e) { log.warn("Your xerces implemention is too old to support 'external-general-entities' attribute."); } try { dbf.setAttribute("http://xml.org/sax/features/external-parameter-entities", false); } catch (IllegalArgumentException e) { log.warn("Your xerces implemention is too old to support 'external-parameter-entities' attribute."); } try { dbf.setAttribute("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); } catch (IllegalArgumentException e) { log.warn("Your xerces implemention is too old to support 'load-external-dtd' attribute."); } return dbf; } // ??ErrorHandler private static final ErrorHandler EH = new ErrorHandler() { public void error(SAXParseException x) throws SAXException { throw x; } public void fatalError(SAXParseException x) throws SAXException { throw x; } public void warning(SAXParseException x) throws SAXException { log.warn("SAXParserWarnning:", x); } }; /** * ??DTD?classpathDTD????DTD */ private static final EntityResolver ER = new EntityResolver() { public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { if (systemId != null && systemId.endsWith(".dtd")) { URL url = new URL(systemId); String file = StringUtils.substringAfterLastIfExist(url.getFile(), "/"); URL u = this.getClass().getClassLoader().getResource(file); if (u == null) { u = url; } InputSource source = new InputSource(u.openStream()); source.setPublicId(publicId); source.setSystemId(systemId); return source; } return null; } }; /** * DocumentBuilderCache<br> * ?DocumentBuilder0.4ms?? */ private static final ThreadLocal<DocumentBuilderCache> REUSABLE_BUILDER = new ThreadLocal<DocumentBuilderCache>() { @Override protected DocumentBuilderCache initialValue() { return new DocumentBuilderCache(); } }; /** * DocumentBuilder * * @author jiyi * */ private final static class DocumentBuilderCache { DocumentBuilder cacheTT; DocumentBuilder cacheTF; DocumentBuilder cacheFT; DocumentBuilder cacheFF; /** * ????DocumentBuilder * * @param ignorComments * @param namespaceAware * @return */ private DocumentBuilder getDocumentBuilder(boolean ignorComments, boolean namespaceAware) { if (ignorComments && namespaceAware) { if (cacheTT == null) { cacheTT = initBuilder(domFactoryTT); } return cacheTT; } else if (ignorComments) { if (cacheTF == null) { cacheTF = initBuilder(domFactoryTF); } return cacheTF; } else if (namespaceAware) { if (cacheFT == null) { cacheFT = initBuilder(domFactoryFT); } return cacheFT; } else { if (cacheFF == null) { cacheFF = initBuilder(domFactoryFF); } return cacheFF; } } private DocumentBuilder initBuilder(DocumentBuilderFactory domFactory) { DocumentBuilder builder; try { builder = domFactory.newDocumentBuilder(); } catch (ParserConfigurationException e) { throw new UnsupportedOperationException(e); } builder.setErrorHandler(EH); builder.setEntityResolver(ER); return builder; } } /** * Xpath? */ private static XPathFactory xp = XPathFactory.newInstance(); /** * HTML? */ private static jef.tools.IDOMFragmentParser parser; /** * Json??XML Document(Json-Lib) * * @param json * ??json * @return json??XML * @throws SAXException * @throws IOException */ public static Document loadDocument(JSONObject json) { return XMLFastJsonParser.DEFAULT.toDocument(json); } /** * XML Document?JsonObject,loadDocument(JsonObject json)? * * @param node * ?? * @return ??json */ public static JSONObject toJsonObject(Node node) { return XMLFastJsonParser.DEFAULT.toJsonObject(node); } /** * XML * * @param file * * @return Document ?DOM * @throws SAXException * ? * @throws IOException * ?? */ public static Document loadDocument(File file) throws SAXException, IOException { return loadDocument(file, true); } /** * XML * * @param file * * @param ignorComments * ?XML * @return Document ?DOM * @throws SAXException * @throws IOException */ public static Document loadDocument(File file, boolean ignorComments) throws SAXException, IOException { InputStream in = IOUtils.getInputStream(file); try { Document document = loadDocument(in, null, ignorComments, false); return document; } finally { in.close(); } } /** * ?XML * * @param filename * * @return ?DOM * @throws SAXException * @throws IOException */ public static Document loadDocument(String filename) throws SAXException, IOException { return loadDocument(new File(filename)); } /** * URLXML * * @param reader * @return ?DOM * @throws SAXException * @throws IOException */ public static Document loadDocument(URL url) throws SAXException, IOException { return loadDocument(url.openStream(), null, true, false); } /** * ReaderXML * * @param reader * ? * @param ignorComments * ? * @param namespaceAware * ??? * @return ?DOM * @throws SAXException * @throws IOException */ public static Document loadDocument(Reader reader, boolean ignorComments, boolean namespaceAware) throws SAXException, IOException { try { DocumentBuilder db = REUSABLE_BUILDER.get().getDocumentBuilder(ignorComments, namespaceAware); InputSource is = new InputSource(reader); Document doc = db.parse(is); return doc; } finally { IOUtils.closeQuietly(reader); } } /** * ?xml * * @param xmlContent * XML * @return Document DOM * @throws SAXException * ? * @throws IOException * */ public static Document parse(String xmlContent) throws SAXException, IOException { Reader reader = null; try { reader = new StringReader(xmlContent); return loadDocument(reader, true, false); } finally { IOUtils.closeQuietly(reader); } } /** * ?xml * * @param xmlContent * XML * @return Document ??DOM * @throws SAXException * ? * @throws IOException * * @deprecated use {@link #parse(String)} */ public static Document loadDocumentByString(String xmlContent) throws SAXException, IOException { return parse(xmlContent); } /** * ?XML * * @param in * ? * @param charSet * ? * @param ignorComment * * @return Document ?DOM * @throws SAXException * ? * @throws IOException * */ public static Document loadDocument(InputStream in, String charSet, boolean ignorComment) throws SAXException, IOException { return loadDocument(in, charSet, ignorComment, false); } /** * XML * * @param in * ? * @param charSet * ? * @param ignorComment * * @return Document. DOM * @throws SAXException * ? * @throws IOException * */ public static Document loadDocument(InputStream in, String charSet, boolean ignorComments, boolean namespaceAware) throws SAXException, IOException { DocumentBuilder db = REUSABLE_BUILDER.get().getDocumentBuilder(ignorComments, namespaceAware); InputSource is = null; // ????charset if (charSet == null) {// ?200??? byte[] buf = new byte[200]; PushbackInputStream pin = new PushbackInputStream(in, 200); in = pin; int len = pin.read(buf); if (len > 0) { pin.unread(buf, 0, len); charSet = getCharsetInXml(buf, len); } } if (charSet != null) { is = new InputSource(new XmlFixedReader(new InputStreamReader(in, charSet))); is.setEncoding(charSet); } else { // ? Reader reader = new InputStreamReader(in, "UTF-8");// XML???Reader??Reader?XML? is = new InputSource(new XmlFixedReader(reader)); } Document doc = db.parse(is); doc.setXmlStandalone(true);// True???standalone="no" return doc; } /** * ?XML?xml? * * @param buf * XML * @param len * * @return XML???null */ public static String getCharsetInXml(byte[] buf, int len) { buf = ArrayUtils.subarray(buf, 0, len); String s = new String(buf).toLowerCase(); int n = s.indexOf("encoding="); if (n > -1) { s = s.substring(n + 9); if (s.charAt(0) == '\"' || s.charAt(0) == '\'') { s = s.substring(1); } n = StringUtils.indexOfAny(s, "\"' ><"); if (n > -1) { s = s.substring(0, n); } if (StringUtils.isEmpty(s)) { return null; } s = Charsets.getStdName(s); return s; } else { return null; } } /** * HTML * * @param in * ? * @return DocumentFragment DOM * @throws SAXException * ? * @throws IOException * */ public static DocumentFragment parseHTML(Reader in) throws SAXException, IOException { if (parser == null) throw new UnsupportedOperationException( "HTML parser module not loaded, to activate this feature, you must add JEF common-ioc.jar to classpath"); InputSource source; source = new InputSource(in); synchronized (parser) { HTMLDocument document = new HTMLDocumentImpl(); DocumentFragment fragment = document.createDocumentFragment(); parser.parse(source, fragment); return fragment; } } /** * HTML * * @param in * ? * @param charSet * ? * @return DocumentFragment DOM * @throws SAXException * ? * @throws IOException * */ public static DocumentFragment parseHTML(File file) throws IOException, SAXException { InputStream in = IOUtils.getInputStream(file); try { DocumentFragment document = parseHTML(in, null); return document; } finally { in.close(); } } /** * ?HTMLDocument * * @param url * ? * @return DocumentFragment DOM * @throws SAXException * @throws IOException */ public static DocumentFragment parseHTML(URL url) throws SAXException, IOException { return parseHTML(url.openStream(), null); } /** * ??HTML? * * @param in * ? * @param charSet * null * @return ??DocumentFragment * @throws SAXException * XML * @throws IOException * IO? * @deprecated Use {@link #parseHTML(InputStream, String)} instead. */ public static DocumentFragment loadHtmlDocument(InputStream in, String charSet) throws SAXException, IOException { return parseHTML(in, charSet); } /** * ??HTML * * @param in * ? * @param charSet * null * @return ??DocumentFragment * @throws SAXException * XML * @throws IOException * IO? */ public static DocumentFragment parseHTML(InputStream in, String charSet) throws SAXException, IOException { if (parser == null) throw new UnsupportedOperationException( "HTML parser module not loaded, to activate this feature, you must add JEF common-ioc.jar to classpath"); InputSource source; if (charSet != null) { source = new InputSource(new XmlFixedReader(new InputStreamReader(in, charSet))); source.setEncoding(charSet); } else { source = new InputSource(in); } synchronized (parser) { HTMLDocument document = new HTMLDocumentImpl(); DocumentFragment fragment = document.createDocumentFragment(); parser.parse(source, fragment); return fragment; } } /** * ?XML * * @param doc * DOM * @param file * ? * @throws IOException * */ public static void saveDocument(Node doc, File file) throws IOException { saveDocument(doc, file, "UTF-8"); } /** * ?XML * * @param doc * DOM * @param file * * @param encoding * ? * @throws IOException */ public static void saveDocument(Node doc, File file, String encoding) throws IOException { OutputStream os = IOUtils.getOutputStream(file); try { output(doc, os, encoding); } finally { os.close(); } } /** * XML? * * @param node * DOM * @param os * ? * @throws IOException * */ public static void output(Node node, OutputStream os) throws IOException { output(node, os, null, 4, null); } /** * XML? * * @param node * DOM * @param os * ? * @param encoding * ? * @throws IOException * */ public static void output(Node node, OutputStream os, String encoding) { output(node, os, encoding, 4, null); } /** * ?String * * @param node * DOM * @return ??XML */ public static String toString(Node node) { return toString(node, null); } /** * XML? * * @param node * DOM * @param os * ? * @param encoding * ? * @param warpLine * * @param xmlDeclare * nulldocument?xmltrue? false * @throws IOException * */ public static void output(Node node, OutputStream os, String encoding, int warpLine, Boolean xmlDeclare) { try { StreamResult sr = new StreamResult( encoding == null ? new OutputStreamWriter(os) : new OutputStreamWriter(os, encoding)); output(node, sr, encoding, warpLine, xmlDeclare); } catch (IOException e) { throw new RuntimeException(e); } } /** * ? * * @param node * ??Document * @param os * ? * @param encoding * ? * @param warpLine * ?? * @throws IOException * */ public static void output(Node node, Writer os, String encoding, int indent) throws IOException { StreamResult sr = new StreamResult(os); output(node, sr, encoding, indent, null); } private static void output(Node node, StreamResult sr, String encoding, int indent, Boolean XmlDeclarion) throws IOException { if (node.getNodeType() == Node.ATTRIBUTE_NODE) { sr.getWriter().write(node.getNodeValue()); sr.getWriter().flush(); return; } TransformerFactory tf = TransformerFactory.newInstance(); Transformer t = null; try { if (indent > 0) { try { tf.setAttribute("indent-number", indent); t = tf.newTransformer(); // ?XML??XML? t.setOutputProperty(OutputKeys.INDENT, "yes"); } catch (Exception e) { } } else { t = tf.newTransformer(); } t.setOutputProperty(OutputKeys.METHOD, "xml"); if (encoding != null) { t.setOutputProperty(OutputKeys.ENCODING, encoding); } if (XmlDeclarion == null) { XmlDeclarion = (node instanceof Document); } if (node instanceof Document) { Document doc = (Document) node; if (doc.getDoctype() != null) { t.setOutputProperty(javax.xml.transform.OutputKeys.DOCTYPE_PUBLIC, doc.getDoctype().getPublicId()); t.setOutputProperty(javax.xml.transform.OutputKeys.DOCTYPE_SYSTEM, doc.getDoctype().getSystemId()); } } if (XmlDeclarion) { t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); } else { t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); } } catch (Exception tce) { throw new IOException(tce); } DOMSource doms = new DOMSource(node); try { t.transform(doms, sr); } catch (TransformerException te) { IOException ioe = new IOException(); ioe.initCause(te); throw ioe; } } /** * CDATA * * @param node * * @param data * CDATA * @return ?CDATA */ public static CDATASection addCDataText(Node node, String data) { Document doc = null; if (node.getNodeType() == Node.DOCUMENT_NODE) { doc = (Document) node; } else { doc = node.getOwnerDocument(); } CDATASection e = doc.createCDATASection(data); node.appendChild(e); return e; } /** * XPath * * @param startPoint * * @param expr * xpath? * @return xpath? * @throws XPathExpressionException */ public static String evalXpath(Object startPoint, String expr) throws XPathExpressionException { XPath xpath = xp.newXPath(); return xpath.evaluate(expr, startPoint); } /** * XPATH * * @param startPoint * * @param expr * xpath? * @return xpath * @throws XPathExpressionException */ public static Node selectNode(Object startPoint, String expr) throws XPathExpressionException { XPath xpath = xp.newXPath(); return (Node) xpath.evaluate(expr, startPoint, XPathConstants.NODE); } /** * XPATH * * @param startPoint * * @param expr * xpath? * @return ?xpath * @throws XPathExpressionException */ public static NodeList selectNodes(Object startPoint, String expr) throws XPathExpressionException { XPath xpath = xp.newXPath(); return (NodeList) xpath.evaluate(expr, startPoint, XPathConstants.NODESET); } /** * XPATH * * @param start * @param expr * @return * @throws XPathExpressionException */ public static List<Element> selectElements(Node start, String expr) throws XPathExpressionException { return toElementList(selectNodes(start, expr)); } /** * ? * * @param node * * @param data * * @return DOM */ public static Text setText(Node node, String data) { Document doc = null; if (node.getNodeType() == Node.DOCUMENT_NODE) { doc = (Document) node; } else { doc = node.getOwnerDocument(); } clearChildren(node, Node.TEXT_NODE); Text t = doc.createTextNode(data); node.appendChild(t); return t; } /** * ? * * @param node * * @param comment * * @return Comment */ public static Comment addComment(Node node, String comment) { Document doc = null; if (node.getNodeType() == Node.DOCUMENT_NODE) { doc = (Document) node; } else { doc = node.getOwnerDocument(); } Comment e = doc.createComment(comment); node.appendChild(e); return e; } /** * ?? * * <pre> * <parent> * <a>text-a</a> * <c>text-c</c> * </parent> * </pre> * * {@code addElementBefore(c,"b","text-b")}c?c * * <pre> * <parent> * <a>text-a</a> * <b>text-b</b> * <c>text-c</c> * </parent> * </pre> * * @param node * DOM * @param tagName * ?? * @param nodeText * * @return Element */ public static Element addElementBefore(Node node, String tagName, String... nodeText) { Node pNode = node.getParentNode(); List<Node> movingNodes = new ArrayList<Node>(); for (Node n : toArray(pNode.getChildNodes())) { if (n == node) { movingNodes.add(n); } else if (movingNodes.size() > 0) { movingNodes.add(n); } } Element e = addElement(pNode, tagName, nodeText); for (Node n : movingNodes) { pNode.appendChild(n); } return e; } /** * ?? * * @param node * DOM * @param tagName * ?? * @param nodeText * * @return Element */ public static Element addElementAfter(Node node, String tagName, String... nodeText) { Node pNode = node.getParentNode(); List<Node> movingNodes = new ArrayList<Node>(); boolean flag = false; for (Node n : toArray(pNode.getChildNodes())) { if (flag) { movingNodes.add(n); } else if (n == node) { flag = true; } } Element e = addElement(pNode, tagName, nodeText); for (Node n : movingNodes) { pNode.appendChild(n); } return e; } /** * ??? * * @param node * * @param tagName * ?? * @param nodeText * * @return Element */ public static Element replaceElement(Node node, String tagName, String... nodeText) { Node pNode = node.getParentNode(); Assert.notNull(pNode); Document doc = null; if (node.getNodeType() == Node.DOCUMENT_NODE) { doc = (Document) node; } else { doc = node.getOwnerDocument(); } Element e = doc.createElement(tagName); if (nodeText.length == 1) { setText(e, nodeText[0]); } else if (nodeText.length > 1) { setText(e, StringUtils.join(nodeText, '\n')); } pNode.replaceChild(e, node); return e; } /** * Element * * @param parent * * @param tagName * ??? * @param attribName * ?? * @param attribValue * * @return */ public static Element getOrCreateChildElement(Node parent, String tagName, String attribName, String attribValue) { for (Element e : XMLUtils.childElements(parent, tagName)) { if (attribValue == null || attribValue.equals(XMLUtils.attrib(e, attribName))) { return e; } } Element e = XMLUtils.addElement(parent, tagName); e.setAttribute(attribName, attribValue); return e; } /** * TagName * * @param node * * @param tagName * ??? * @return ? */ public static int removeChildElements(Node node, String... tagName) { List<Element> list = XMLUtils.childElements(node, tagName); for (Element e : list) { node.removeChild(e); } return list.size(); } /** * ??? * * @param node * */ public static void clearChildren(Node node) { clearChildren(node, 0); } /** * * * @param node * @param type * ??NodeType0 */ public static void clearChildren(Node node, int type) { for (Node child : toArray(node.getChildNodes())) { if (type == 0 || child.getNodeType() == type) { node.removeChild(child); } } } /** * * * @param element * ? */ public static void clearAttribute(Element element) { for (Node node : toArray(element.getAttributes())) { element.removeAttributeNode((Attr) node); } } /** * ? * * @param element * ? */ public static void clearChildrenAndAttr(Element element) { clearChildren(element); clearAttribute(element); } /** * ? * * @param node * * @param tagName * ?? * @param nodeText * * @return Element */ public static Element addElement(Node node, String tagName, String... nodeText) { Document doc = null; if (node.getNodeType() == Node.DOCUMENT_NODE) { doc = (Document) node; } else { doc = node.getOwnerDocument(); } Element e = doc.createElement(tagName); node.appendChild(e); if (nodeText.length == 1) { setText(e, nodeText[0]); } else if (nodeText.length > 1) { setText(e, StringUtils.join(nodeText, '\n')); } return e; } /** * ????? * * @param node * ???? * @param newName * ?? * @return ????DOMElement */ public static Element changeNodeName(Element node, String newName) { Document doc = node.getOwnerDocument(); Element newEle = doc.createElement(newName); Node parent = node.getParentNode(); parent.removeChild(node); parent.appendChild(newEle); for (Node child : toArray(node.getChildNodes())) { node.removeChild(child); newEle.appendChild(child); } return newEle; } /** * Element(??) * * @param node * * @param tagName * ????nullElement * @return ?? */ public static List<Element> childElements(Node node, String... tagName) { if (node == null) throw new NullPointerException("the input node can not be null!"); List<Element> list = new ArrayList<Element>(); NodeList nds = node.getChildNodes(); if (tagName.length == 0 || tagName[0] == null) {// ?API tagName = null; } for (int i = 0; i < nds.getLength(); i++) { Node child = nds.item(i); if (child.getNodeType() == Node.ELEMENT_NODE) { Element e = (Element) child; if (tagName == null || ArrayUtils.contains(tagName, e.getNodeName())) { list.add(e); } } else if (child.getNodeType() == Node.CDATA_SECTION_NODE) { } else if (child.getNodeType() == Node.COMMENT_NODE) { } else if (child.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE) { } else if (child.getNodeType() == Node.DOCUMENT_NODE) { } else if (child.getNodeType() == Node.DOCUMENT_TYPE_NODE) { } else if (child.getNodeType() == Node.ATTRIBUTE_NODE) { } else if (child.getNodeType() == Node.TEXT_NODE) { } } return list; } static class MyNodeList implements NodeList { Node[] list; public int getLength() { return list.length; } public Node item(int index) { return list[index]; } public MyNodeList(Node[] list) { this.list = list; } public MyNodeList(List<? extends Node> list) { this.list = list.toArray(new Node[list.size()]); } } /** * ?(Trimed) * * @param element * * @return xml */ public static String nodeText(Node element) { Node first = first(element, Node.TEXT_NODE, Node.CDATA_SECTION_NODE); if (first != null && first.getNodeType() == Node.CDATA_SECTION_NODE) { return ((CDATASection) first).getTextContent(); } StringBuilder sb = new StringBuilder(); if (first == null || StringUtils.isBlank(first.getTextContent())) { for (Node n : toArray(element.getChildNodes())) { if (n.getNodeType() == Node.TEXT_NODE) { sb.append(n.getTextContent()); } else if (n.getNodeType() == Node.CDATA_SECTION_NODE) { sb.append(((CDATASection) n).getTextContent()); } } } else { sb.append(first.getTextContent()); } return StringUtils.trimToNull(StringEscapeUtils.unescapeHtml(sb.toString())); } /** * text * * @param element * * @param withChildren * ??? * @return xml */ public static String nodeText(Node element, boolean withChildren) { StringBuilder sb = new StringBuilder(); for (Node node : toArray(element.getChildNodes())) { if (node.getNodeType() == Node.TEXT_NODE) { sb.append(node.getNodeValue().trim()); } else if (node.getNodeType() == Node.CDATA_SECTION_NODE) { sb.append(((CDATASection) node).getTextContent()); } else if (withChildren) { if (node.getNodeType() == Node.ELEMENT_NODE) { sb.append(nodeText((Element) node, true)); } } } return sb.toString(); } /** * * * @param e * * @param attributeName * ?? * @return xml */ public static String attrib(Element e, String attributeName) { if (!e.hasAttribute(attributeName)) return null; String text = e.getAttribute(attributeName); return (text == null) ? null : StringEscapeUtils.unescapeXml(text.trim()); } /** * (???) * * @param e * * @param attributeName * ?? * @return ??List */ public static List<String> attribs(Element e, String attributeName) { List<String> _list = new ArrayList<String>(); if (e.hasAttribute(attributeName)) { String text = e.getAttribute(attributeName); _list.add((text == null) ? null : StringEscapeUtils.unescapeHtml(text.trim())); } if (e.hasChildNodes()) { NodeList nds = e.getChildNodes(); for (int i = 0; i < nds.getLength(); i++) { Node child = nds.item(i); if (child.getNodeType() == Node.ELEMENT_NODE) { _list.addAll(attribs((Element) child, attributeName)); } } } return _list; } /** * ???(Trim) * * @param element * * @param subEleName * ??? * @return ?xml */ public static String nodeText(Element element, String subEleName) { Element e = first(element, subEleName); if (e == null) return null; return nodeText(e); } /** * n(?) * * @param parent * * @param elementName * ?? * @param index * ?? * @return DOM */ public static Element nthElement(Element parent, String elementName, int index) { NodeList nds = parent.getElementsByTagName(elementName); if (nds.getLength() < index) throw new NoSuchElementException(); Element node = (Element) nds.item(index - 1); return node; } /** * ??Tag Name? * * @param parent * * @param elementName * ??? * @return ?? */ public static Element first(Node node, String tagName) { if (node == null) return null; NodeList nds = node.getChildNodes(); for (int i = 0; i < nds.getLength(); i++) { Node child = nds.item(i); if (child.getNodeType() == Node.ELEMENT_NODE) { Element e = (Element) child; if (tagName == null || tagName.equals(e.getNodeName())) { return e; } // } else if (child.getNodeType() == Node.CDATA_SECTION_NODE) { // } else if (child.getNodeType() == Node.COMMENT_NODE) { // } else if (child.getNodeType() == // Node.DOCUMENT_FRAGMENT_NODE) { // } else if (child.getNodeType() == Node.DOCUMENT_NODE) { // } else if (child.getNodeType() == Node.DOCUMENT_TYPE_NODE) { // } else if (child.getNodeType() == Node.ATTRIBUTE_NODE) { // } else if (child.getNodeType() == Node.TEXT_NODE) { } } return null; } /** * ?(?) * * @param node * * @param nodeType * Node?{@link Node#ELEMENT_NODE}? * {@link Node#DOCUMENT_NODE} * @return */ public static Node first(Node node, int... nodeType) { if (node == null) return null; NodeList nds = node.getChildNodes(); for (int i = 0; i < nds.getLength(); i++) { Node child = nds.item(i); if (ArrayUtils.contains(nodeType, child.getNodeType())) { return child; } } return null; } /** * XML * * @param tagName * ?? * @return Document */ public static Document newDocument(String tagName) { Assert.notNull(tagName); Document doc = newDocument(); addElement(doc, tagName); return doc; } /** * XML * * @return XML */ public static Document newDocument() { try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.newDocument(); document.setXmlStandalone(true); return document; } catch (ParserConfigurationException e) { LogUtil.exception(e); return null; } } /** * NamedNodeMap?Node * * @param nds * NamedNodeMap * @return Node */ public static Node[] toArray(NamedNodeMap nds) { Node[] array = new Node[nds.getLength()]; for (int i = 0; i < nds.getLength(); i++) { array[i] = nds.item(i); } return array; } /** * Map * * @param e * * @param attrMap * * @param isSubNode * ?false,true? */ public static void setAttributesByMap(Element e, Map<String, Object> attrMap, boolean isSubNode) { if (attrMap == null) return; setAttrMap(e, attrMap, isSubNode); } /** * Map * * @param e * * @param map * */ public static void setAttributesByMap(Element e, Map<String, Object> map) { setAttributesByMap(e, map, false); } @SuppressWarnings("rawtypes") private static void setAttrMap(Element e, Map attrMap, boolean isSubNode) { if (isSubNode) { for (Object keyObj : attrMap.keySet()) { String key = StringUtils.toString(keyObj); Object value = attrMap.get(key); if (value.getClass().isArray()) { setAttrArray(e, key, (Object[]) value, isSubNode); continue; } else if (value instanceof List) { setAttrArray(e, key, ((List) value).toArray(), isSubNode); continue; } Element child = first(e, key); if (child == null) { child = addElement(e, key); } if (value instanceof Map) { setAttrMap(child, (Map) value, isSubNode); } else { setText(child, StringUtils.toString(value)); } } } else { for (Object keyObj : attrMap.keySet()) { String key = StringUtils.toString(keyObj); Object value = attrMap.get(key); if (value instanceof Map) { Element child = first(e, key); if (child == null) { child = addElement(e, key); } setAttrMap(child, (Map) value, isSubNode); } else if (value.getClass().isArray()) { setAttrArray(e, key, (Object[]) value, isSubNode); } else if (value instanceof List) { setAttrArray(e, key, ((List) value).toArray(), isSubNode); } else { e.setAttribute(key, StringUtils.toString(value)); } } } } @SuppressWarnings("rawtypes") private static void setAttrArray(Element e, String key, Object[] value, boolean isSubNode) { for (Object o : value) { if (o instanceof Map) { Element child = addElement(e, key); setAttrMap(child, (Map) o, isSubNode); } else { Element child = addElement(e, key); setText(child, StringUtils.toString(o)); } } } /** * ? * * @param parent * * @param tagName * ???? * @param value * */ public static void setNodeText(Element parent, String tagName, String value) { Element child = first(parent, tagName); if (child != null) { setText(child, value); } } /** * ?Map? * * @param e * * @return ???Map */ public static Map<String, String> getAttributesMap(Element e) { return getAttributesMap(e, false); } /** * ? * * @param e * * @param subElementAsAttr * trueElement?<br> * * * <pre> * <Foo size="103" name="Karen"> * <dob>2012-4-12</dobh> * <dod>2052-4-12</dodh> * </Foo> * </pre> * * subElementAsAttr=falsedob,dod?true? * @return */ public static Map<String, String> getAttributesMap(Element e, boolean subElementAsAttr) { Map<String, String> attribs = new HashMap<String, String>(); if (e == null) return attribs; NamedNodeMap nmp = e.getAttributes(); for (int i = 0; i < nmp.getLength(); i++) { Attr child = (Attr) nmp.item(i); attribs.put(StringEscapeUtils.unescapeHtml(child.getName()), StringEscapeUtils.unescapeHtml(child.getValue())); } if (subElementAsAttr) { NodeList nds = e.getChildNodes(); for (int i = 0; i < nds.getLength(); i++) { Node node = nds.item(i); if (node.getNodeType() != Node.ELEMENT_NODE) continue; Element sub = (Element) node; String key = sub.getNodeName(); String value = nodeText(sub); if (attribs.containsKey(key)) { attribs.put(key, attribs.get(key) + "," + value); } else { attribs.put(key, value); } } } return attribs; } /** * ? * * <pre> * <object> * <id>100</id> * <name>Jhon smith</name> * <phone>130100000</phone> * <object> * </pre> * * ? * {@code getAttributesInChildElements(objectNode, "name", "phone")}? * {name="Jhon smith"phone="130100000"}Map * ?????Map * * @param parent * * @param keys * ? * @return ????Map */ public static Map<String, String> getAttributesInChildElements(Element parent, String... keys) { NodeList nds = parent.getChildNodes(); Map<String, String> attribs = new HashMap<String, String>(); for (int i = 0; i < nds.getLength(); i++) { Node node = nds.item(i); if (node.getNodeType() != Node.ELEMENT_NODE) continue; Element sub = (Element) node; String key = sub.getNodeName(); if (keys.length == 0 || ArrayUtils.contains(keys, key)) { String value = nodeText(sub); if (attribs.containsKey(key)) { attribs.put(key, attribs.get(key) + "," + value); } else { attribs.put(key, value); } } } return attribs; } /** * * * <pre> * <object> * <id>100</id> * <name>Jhon smith</name> * <phone>130100000</phone> * <object> * </pre> * * XML?? * * <pre> * <object id="100" name="Jhon smith" pone="130100000"> * </object> * </pre> * * ? * * @param e * ?? * @param keys * ?? */ public static void moveChildElementAsAttribute(Element e, String... keys) { NodeList nds = e.getChildNodes(); for (Node node : toArray(nds)) { if (node.getNodeType() == Node.TEXT_NODE) { e.removeChild(node); // } if (node.getNodeType() != Node.ELEMENT_NODE) continue; Element sub = (Element) node; String key = sub.getNodeName(); if (keys.length == 0 || ArrayUtils.contains(keys, key)) { String value = nodeText(sub); e.setAttribute(key, value); e.removeChild(sub); } } } /** * XML?Java * * @param e * * @param clz * ??java * @throws ReflectionException * ?? * @deprecated loadBean(Element,Class) */ public static <W> W elementToBean(Element e, Class<W> clz) throws ReflectionException { return loadBean(e, clz); } /** * XML?Java * <p> * ??putBean?????load bean?load * beanbean??? putBean * * @param e * * @param bean * ??java * @throws ReflectionException * ?? */ public static <W> W loadBean(Element e, Class<W> clz) { W bean = UnsafeUtils.newInstance(clz); BeanWrapperImpl bw = new BeanWrapperImpl(bean); Map<String, String> attrs = getAttributesMap(e, true); for (String key : bw.getPropertyNames()) { if (attrs.containsKey(key)) { bw.setPropertyValueByString(key, attrs.get(key)); } } return bean; } /** * java bean?XML ???XML? * * @param parent * ? * @param bean * ? * @return ?? */ public static Element putBean(Node parent, Object bean) { if (bean == null) return null; return appendBean(parent, bean, bean.getClass(), null, null); } /** * java bean?XML ???XML? * * * @param node * ? * @param bean * ? * @param tryAttribute * true?XML falseXML * null??? * @return ?? */ public static Element putBean(Node node, Object bean, Boolean tryAttribute) { if (bean == null) return null; return appendBean(node, bean, bean.getClass(), tryAttribute, null); } /** * ??Document?<br/> * ???Document? * * @param parent * * @param nodes * ??? */ public static void appendChild(Node parent, Node... nodes) { Document doc = parent.getOwnerDocument(); for (Node node : nodes) { if (node.getOwnerDocument() != doc) { parent.appendChild(doc.importNode(node, true)); } else { parent.appendChild(node); } } } /** * NodeList? * * @param nds * NodeList * @return Node */ public static Node[] toArray(NodeList nds) { if (nds instanceof MyNodeList) return ((MyNodeList) nds).list; Node[] array = new Node[nds.getLength()]; for (int i = 0; i < nds.getLength(); i++) { array[i] = nds.item(i); } return array; } /** * NodeList?List * * @param nds * NodeList * @return Node?List */ public static List<? extends Node> toList(NodeList nds) { if (nds instanceof MyNodeList) return Arrays.asList(((MyNodeList) nds).list); List<Node> list = new ArrayList<Node>(); for (int i = 0; i < nds.getLength(); i++) { Node child = nds.item(i); list.add(child); } return list; } /** * Nodelist?Element List * * @param nds * NodeList * @return NodeListElement?List */ public static List<Element> toElementList(NodeList nds) { List<Element> list = new ArrayList<Element>(); for (int i = 0; i < nds.getLength(); i++) { Node child = nds.item(i); if (child.getNodeType() == Node.ELEMENT_NODE) { list.add((Element) child); } } return list; } /** * Node?NodeList{@link #toList(NodeList)}? * * @param list * Node * @return NodeList */ public static NodeList toNodeList(List<? extends Node> list) { return new MyNodeList(list); } /** * Node?NodeList{@link #toArray(NodeList)}? * * @param array * Node * @return NodeList */ public static NodeList toNodeList(Node[] array) { return new MyNodeList(array); } /** * ?? * * @param node * ? * @param text * * @param searchAttribute * ? * @return Node?null */ public static Node findFirst(Node node, String text, boolean searchAttribute) { String value = getValue(node); if (value != null && value.indexOf(text) > -1) return node; if (searchAttribute && node.getAttributes() != null) { for (Node n : toArray(node.getAttributes())) { value = getValue(n); if (value != null && value.indexOf(text) > -1) return n; } } for (Node sub : toArray(node.getChildNodes())) { Node nd = findFirst(sub, text, searchAttribute); if (nd != null) return nd; } return null; } /** * * * @param node * ? * @param text * * @param searchAttribute * ? */ public static void removeNodeWithKeyword(Node node, String text, boolean searchAttribute) { String value = getValue(node); if (value != null && value.indexOf(text) > -1) { node.getParentNode().removeChild(node); return; } if (searchAttribute && node.getAttributes() != null) { for (Node n : toArray(node.getAttributes())) { value = getValue(n); if (value != null && value.indexOf(text) > -1) { node.getParentNode().removeChild(node); return; } } } for (Node sub : toArray(node.getChildNodes())) { removeNodeWithKeyword(sub, text, searchAttribute); } } /** * ?? * * @param node * * @param text * * @param searchAttribute * ? * @return Node? */ public static Node[] find(Node node, String text, boolean searchAttribute) { List<Node> result = new ArrayList<Node>(); innerSearch(node, text, result, searchAttribute); return result.toArray(new Node[0]); } /** * ??Element?? * * @param root * * @param tagName * ??element?? * @param attribName * ???? * @param keyword * ?? * @return ?? */ public static Element findElementByNameAndAttribute(Node root, String tagName, String attribName, String keyword) { Element[] es = findElementsByNameAndAttribute(root, tagName, attribName, keyword, true); if (es.length > 0) return es[0]; return null; } /** * ??Element?? * * @param root * * @param tagName * ??element?? * @param attribName * ???? * @param keyword * ?? * @return ?? */ public static Element[] findElementsByNameAndAttribute(Node root, String tagName, String attribName, String keyword) { return findElementsByNameAndAttribute(root, tagName, attribName, keyword, false); } /** * ?Element * * @param node * * @param attribName * ?? * @param keyword * ?? * @return ??Element */ public static Element findElementByAttribute(Node node, String attribName, String keyword) { Element[] result = findElementsByAttribute(node, attribName, keyword, true); if (result.length == 0) return null; return result[0]; } /** * Element,? * * @param node * * @param attribName * ?? * @param keyword * * @return ?? */ public static Element[] findElementsByAttribute(Node node, String attribName, String keyword) { return findElementsByAttribute(node, attribName, keyword, false); } /** * ?attribid?JSdocument.getElementById(); * * @param node * * @param id * ID * @return */ public static Element findElementById(Node node, String id) { if (node == null) return null; if (node.getNodeType() == Node.ELEMENT_NODE) { Element e = (Element) node; if (e.hasAttribute("id")) { String ss = StringUtils.trim(e.getAttribute("id")); if (ss.equals(id)) { return e; } } } for (Node sub : toArray(node.getChildNodes())) { Element nd = findElementById(sub, id); if (nd != null) return nd; } return null; } /** * ???tagNameElement * * @param node * * @param tagName * ????? * @return ? */ public static Element firstParent(Node node, String tagName) { if (StringUtils.isEmpty(tagName)) return (Element) node.getParentNode(); Node p = node.getParentNode(); while (p != null) { if (p.getNodeType() == Node.ELEMENT_NODE && p.getNodeName().equals(tagName)) { return (Element) p; } p = p.getParentNode(); } return null; } /** * ?? * * @param node * * @param tagName * ???? * @return ? */ public static Element firstSibling(Node node, String tagName) { Node p = node.getNextSibling(); while (p != null) { if (p.getNodeType() == Node.ELEMENT_NODE) { if (StringUtils.isEmpty(tagName) || p.getNodeName().equals(tagName)) return (Element) p; } p = p.getNextSibling(); } return null; } /** * ???? * * @param node * * @param tagName * ???? * @return ? */ public static Element firstPrevSibling(Node node, String tagName) { Node p = node.getPreviousSibling(); while (p != null) { if (p.getNodeType() == Node.ELEMENT_NODE) { if (StringUtils.isEmpty(tagName) || p.getNodeName().equals(tagName)) return (Element) p; } p = p.getPreviousSibling(); } return null; } /** * xml * <p/> * XMLParser??? * ??? * ???ReadernioStreamReader?read(char[] b, int * off, int len). ??XmlFixedReader??? * <ol> * <li>0x00 - 0x08</li> * <li>0x0b - 0x0c</li> * <li>0x0e - 0x1f</li> * </ol> */ public static class XmlFixedReader extends FilterReader { public XmlFixedReader(Reader reader) { super(new BufferedReader(reader)); } public int read() throws IOException { int ch = super.read(); while ((ch >= 0x00 && ch <= 0x08) || (ch >= 0x0b && ch <= 0x0c) || (ch >= 0x0e && ch <= 0x1f) || ch == 0xFEFF) { ch = super.read(); } return ch; } // ??? public int read(char[] b, int off, int len) throws IOException { if (b == null) { throw new NullPointerException(); } else if (off < 0 || len < 0 || len > b.length - off) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } int c = read(); if (c == -1) { return -1; } b[off] = (char) c; int i = 1; try { for (; i < len; i++) { c = read(); if (c == -1) { break; } b[off + i] = (char) c; } } catch (IOException ee) { } return i; } } /** * Tagnameelement * * @param node * * @param tagName * ?? * @return ?? */ public static List<Element> getElementsByTagNames(Node node, String... tagName) { List<Element> nds = new ArrayList<Element>(); if (tagName.length == 0) tagName = new String[] { "" }; if (node.getNodeType() == Node.ELEMENT_NODE) { Element doc = (Element) node; for (String elementName : tagName) { nds.addAll(toElementList(doc.getElementsByTagName(elementName))); } } else if (node instanceof Document) { Document doc = ((Document) node); for (String elementName : tagName) { nds.addAll(toElementList(doc.getElementsByTagName(elementName))); } } else if (node instanceof DocumentFragment) { Document doc = ((DocumentFragment) node).getOwnerDocument(); for (String elementName : tagName) { nds.addAll(toElementList(doc.getElementsByTagName(elementName))); } } else { throw new IllegalArgumentException("a node who doesn't support getElementsByTagName operation."); } return nds; } /** * Node?? * * @param node * DOM * @param out * ? */ public static void printNode(Node node, OutputStream out) { output(node, out, null, 4, null); } /** * DOM? * * @param node * DOM * @param charset * ??xmlstring?unicode string * ???. * @param xmlHeader * ???XML<?xml ....> * @return ??XML */ public static String toString(Node node, String charset, Boolean xmlHeader) { if (node.getNodeType() == Node.ATTRIBUTE_NODE) { return node.getNodeValue(); } StringWriter sw = new StringWriter(4096); StreamResult sr = new StreamResult(sw); try { output(node, sr, charset, 4, xmlHeader); } catch (IOException e) { LogUtil.exception(e); } return sw.toString(); } /** * DOMXML * * @param node * DOM * @param charset * ??xmlstring?unicode string * ???. * @return ??XML */ public static String toString(Node node, String charset) { return toString(node, charset, null); } /** * XSD Schema * * @param node * DOM * @param schemaURL * XSDURL */ public static void setXsdSchema(Node node, String schemaURL) { Document doc; if (node.getNodeType() != Node.DOCUMENT_NODE) { doc = node.getOwnerDocument(); } else { doc = (Document) node; } Element root = doc.getDocumentElement(); if (schemaURL == null) { root.removeAttribute("xmlns:xsi"); root.removeAttribute("xsi:noNamespaceSchemaLocation"); } else { root.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); root.setAttribute("xsi:noNamespaceSchemaLocation", schemaURL); } } private static void innerSearch(Node node, String text, List<Node> result, boolean searchAttribute) { String value = getValue(node); // if (value != null && value.indexOf(text) > -1) result.add(node); // if (searchAttribute && node.getAttributes() != null) { for (Node n : toArray(node.getAttributes())) { value = getValue(n); if (value != null && value.indexOf(text) > -1) { result.add(n); } } } // for (Node sub : toArray(node.getChildNodes())) { innerSearch(sub, text, result, searchAttribute); } } /* * */ private static String getValue(Node node) { switch (node.getNodeType()) { case Node.ELEMENT_NODE: return nodeText((Element) node); case Node.TEXT_NODE: return StringUtils.trimToNull(StringEscapeUtils.unescapeHtml(node.getTextContent())); case Node.CDATA_SECTION_NODE: return ((CDATASection) node).getTextContent(); default: return StringEscapeUtils.unescapeHtml(node.getNodeValue()); } } private static void innerSearchByAttribute(Node node, String attribName, String id, List<Element> result, boolean findFirst) { if (node.getNodeType() == Node.ELEMENT_NODE) { Element e = (Element) node; String s = attrib(e, attribName); if (s != null && s.equals(id)) { result.add(e); if (findFirst) return; } } for (Node sub : toArray(node.getChildNodes())) { innerSearchByAttribute(sub, attribName, id, result, findFirst); if (findFirst && result.size() > 0) return; } } private static Element[] findElementsByNameAndAttribute(Node root, String tagName, String attribName, String keyword, boolean findFirst) { List<Element> result = new ArrayList<Element>(); List<Element> es; if (root instanceof Document) { es = toElementList(((Document) root).getElementsByTagName(tagName)); } else if (root instanceof Element) { es = toElementList(((Element) root).getElementsByTagName(tagName)); } else if (root instanceof DocumentFragment) { Element eRoot = (Element) first(root, Node.ELEMENT_NODE); es = toElementList(eRoot.getElementsByTagName(tagName)); if (eRoot.getNodeName().equals(tagName)) es.add(eRoot); } else { throw new UnsupportedOperationException(root + " is a unknow Node type to find"); } for (Element e : es) { String s = attrib(e, attribName); if (s != null && s.equals(keyword)) { result.add(e); if (findFirst) break; } } return result.toArray(new Element[result.size()]); } private static Element[] findElementsByAttribute(Node node, String attribName, String keyword, boolean findFirst) { List<Element> result = new ArrayList<Element>(); innerSearchByAttribute(node, attribName, keyword, result, findFirst); return result.toArray(new Element[0]); } private static Element appendBean(Node parent, Object bean, Class<?> type, Boolean asAttrib, String tagName) { if (type == null) { if (bean == null) { return null; } type = bean.getClass(); } if (tagName == null || tagName.length() == 0) { tagName = type.getSimpleName(); } if (type.isArray()) { if (bean == null) return null; Element collection = addElement(parent, tagName); for (int i = 0; i < Array.getLength(bean); i++) { appendBean(collection, Array.get(bean, i), null, asAttrib, null); } return collection; } else if (Collection.class.isAssignableFrom(type)) { if (bean == null) return null; Element collection = addElement(parent, tagName); for (Object obj : (Collection<?>) bean) { appendBean(collection, obj, null, asAttrib, null); } return collection; } else if (Map.class.isAssignableFrom(type)) { Element map = addElement(parent, tagName); for (Entry<?, ?> e : ((Map<?, ?>) bean).entrySet()) { Element entry = XMLUtils.addElement(map, "entry"); Element key = XMLUtils.addElement(entry, "key"); appendBean(key, e.getKey(), null, asAttrib, null); Element value = XMLUtils.addElement(entry, "value"); appendBean(value, e.getValue(), null, asAttrib, null); } return map; } else if (CharSequence.class.isAssignableFrom(type)) { if (Boolean.TRUE.equals(asAttrib)) { ((Element) parent).setAttribute(tagName, StringUtils.toString(bean)); } else { addElement(parent, tagName, StringUtils.toString(bean)); } } else if (Date.class.isAssignableFrom(type)) { if (Boolean.FALSE.equals(asAttrib)) { addElement(parent, tagName, DateUtils.formatDateTime((Date) bean)); } else { ((Element) parent).setAttribute(tagName, DateUtils.formatDateTime((Date) bean)); } } else if (Number.class.isAssignableFrom(type) || type.isPrimitive() || type == Boolean.class) { if (Boolean.FALSE.equals(asAttrib)) { addElement(parent, tagName, StringUtils.toString(bean)); } else { ((Element) parent).setAttribute(tagName, StringUtils.toString(bean)); } } else { if (bean == null) return null; Element root = addElement(parent, type.getSimpleName()); BeanWrapper bw = BeanWrapper.wrap(bean); for (Property p : bw.getProperties()) { appendBean(root, p.get(bean), p.getType(), asAttrib, p.getName()); } return root; } return null; } }