org.macrocloud.kernel.toolkit.utils.XmlUtil Maven / Gradle / Ivy
package org.macrocloud.kernel.toolkit.utils;
import org.springframework.lang.Nullable;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
/**
* xpath解析xml
*
*
* 文档地址:
* http://www.w3school.com.cn/xpath/index.asp
*
*
* @author macro
*/
public class XmlUtil {
/** The path. */
private final XPath path;
/** The doc. */
private final Document doc;
/**
* Instantiates a new xml util.
*
* @param inputSource the input source
* @throws ParserConfigurationException the parser configuration exception
* @throws SAXException the SAX exception
* @throws IOException Signals that an I/O exception has occurred.
*/
private XmlUtil(InputSource inputSource) throws ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory dbf = getDocumentBuilderFactory();
DocumentBuilder db = dbf.newDocumentBuilder();
doc = db.parse(inputSource);
path = getXPathFactory().newXPath();
}
/**
* 创建工具类.
*
* @param inputSource inputSource
* @return XmlUtil
*/
private static XmlUtil create(InputSource inputSource) {
try {
return new XmlUtil(inputSource);
} catch (ParserConfigurationException | SAXException | IOException e) {
throw Exceptions.unchecked(e);
}
}
/**
* 转换工具类.
*
* @param inputStream inputStream
* @return XmlUtil
*/
public static XmlUtil of(InputStream inputStream) {
InputSource inputSource = new InputSource(inputStream);
return create(inputSource);
}
/**
* 转换工具类.
*
* @param xmlStr xmlStr
* @return XmlUtil
*/
public static XmlUtil of(String xmlStr) {
StringReader sr = new StringReader(xmlStr.trim());
InputSource inputSource = new InputSource(sr);
XmlUtil xmlUtil = create(inputSource);
IoUtil.closeQuietly(sr);
return xmlUtil;
}
/**
* 转换路径.
*
* @param expression 表达式
* @param item 实体
* @param returnType 返回类型
* @return Object
*/
private Object evalXPath(String expression, @Nullable Object item, QName returnType) {
item = null == item ? doc : item;
try {
return path.evaluate(expression, item, returnType);
} catch (XPathExpressionException e) {
throw Exceptions.unchecked(e);
}
}
/**
* 获取String.
*
* @param expression 路径
* @return String
*/
public String getString(String expression) {
return (String) evalXPath(expression, null, XPathConstants.STRING);
}
/**
* 获取Boolean.
*
* @param expression 路径
* @return {String}
*/
public Boolean getBoolean(String expression) {
return (Boolean) evalXPath(expression, null, XPathConstants.BOOLEAN);
}
/**
* 获取Number.
*
* @param expression 路径
* @return {Number}
*/
public Number getNumber(String expression) {
return (Number) evalXPath(expression, null, XPathConstants.NUMBER);
}
/**
* 获取某个节点.
*
* @param expression 路径
* @return {Node}
*/
public Node getNode(String expression) {
return (Node) evalXPath(expression, null, XPathConstants.NODE);
}
/**
* 获取子节点.
*
* @param expression 路径
* @return NodeList
*/
public NodeList getNodeList(String expression) {
return (NodeList) evalXPath(expression, null, XPathConstants.NODESET);
}
/**
* 获取String.
*
* @param node 节点
* @param expression 相对于node的路径
* @return String
*/
public String getString(Object node, String expression) {
return (String) evalXPath(expression, node, XPathConstants.STRING);
}
/**
* 获取.
*
* @param node 节点
* @param expression 相对于node的路径
* @return String
*/
public Boolean getBoolean(Object node, String expression) {
return (Boolean) evalXPath(expression, node, XPathConstants.BOOLEAN);
}
/**
* 获取.
*
* @param node 节点
* @param expression 相对于node的路径
* @return Number
*/
public Number getNumber(Object node, String expression) {
return (Number) evalXPath(expression, node, XPathConstants.NUMBER);
}
/**
* 获取某个节点.
*
* @param node 节点
* @param expression 路径
* @return {Node}
*/
public Node getNode(Object node, String expression) {
return (Node) evalXPath(expression, node, XPathConstants.NODE);
}
/**
* 获取子节点.
*
* @param node 节点
* @param expression 相对于node的路径
* @return NodeList
*/
public NodeList getNodeList(Object node, String expression) {
return (NodeList) evalXPath(expression, node, XPathConstants.NODESET);
}
/**
* 针对没有嵌套节点的简单处理.
*
* @return map集合
*/
public Map toMap() {
Element root = doc.getDocumentElement();
Map params = new HashMap<>(16);
// 将节点封装成map形式
NodeList list = root.getChildNodes();
for (int i = 0; i < list.getLength(); i++) {
Node node = list.item(i);
if (node instanceof Element) {
params.put(node.getNodeName(), node.getTextContent());
}
}
return params;
}
/** The prevented XXE. */
private static volatile boolean preventedXXE = false;
/**
* Gets the document builder factory.
*
* @return the document builder factory
* @throws ParserConfigurationException the parser configuration exception
*/
private static DocumentBuilderFactory getDocumentBuilderFactory() throws ParserConfigurationException {
DocumentBuilderFactory dbf = XmlUtil.XmlHelperHolder.documentBuilderFactory;
if (!preventedXXE) {
preventXXE(dbf);
}
return dbf;
}
/**
* preventXXE.
*
* @param dbf the dbf
* @throws ParserConfigurationException the parser configuration exception
*/
private static void preventXXE(DocumentBuilderFactory dbf) throws ParserConfigurationException {
// This is the PRIMARY defense. If DTDs (doctypes) are disallowed, almost all XML entity attacks are prevented
// Xerces 2 only - http://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
// If you can't completely disable DTDs, then at least do the following:
// Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-general-entities
// Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-general-entities
// JDK7+ - http://xml.org/sax/features/external-general-entities
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
// Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-parameter-entities
// Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities
// JDK7+ - http://xml.org/sax/features/external-parameter-entities
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
// Disable external DTDs as well
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
// and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks"
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);
preventedXXE = true;
}
/**
* Gets the x path factory.
*
* @return the x path factory
*/
private static XPathFactory getXPathFactory() {
return XmlUtil.XmlHelperHolder.xPathFactory;
}
/**
* 内部类单例.
*/
private static class XmlHelperHolder {
/** The document builder factory. */
private static DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
/** The x path factory. */
private static XPathFactory xPathFactory = XPathFactory.newInstance();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy