Browse Source

add readBySax

Looly 5 years ago
parent
commit
61c0633da7

+ 1 - 0
CHANGELOG.md

@@ -32,6 +32,7 @@
 * 【core   】     NumberUtil增加isPowerOfTwo方法(pr#1132@Github)
 * 【core   】     优化BooleanUtil的校验逻辑(pr#1137@Github)
 * 【poi    】     改进sax方式读取逻辑,支持sheetId(issue#1141@Github)
+* 【core   】     XmlUtil增加readBySax方法
 
 ### Bug修复
 * 【crypto 】     修复SM2验签后无法解密问题(issue#I1W0VP@Gitee)

+ 97 - 0
hutool-core/src/main/java/cn/hutool/core/util/XmlUtil.java

@@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.exceptions.UtilException;
 import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.IORuntimeException;
 import cn.hutool.core.io.IoUtil;
 import cn.hutool.core.lang.Assert;
 import cn.hutool.core.map.BiMap;
@@ -13,7 +14,11 @@ import org.w3c.dom.Element;
 import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
+import org.xml.sax.ContentHandler;
 import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
 
 import javax.xml.XMLConstants;
 import javax.xml.namespace.NamespaceContext;
@@ -21,6 +26,8 @@ import javax.xml.namespace.QName;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
 import javax.xml.transform.OutputKeys;
 import javax.xml.transform.Result;
 import javax.xml.transform.Source;
@@ -76,6 +83,10 @@ public class XmlUtil {
 	 * 是否打开命名空间支持
 	 */
 	private static boolean namespaceAware = true;
+	/**
+	 * Sax读取器工厂缓存
+	 */
+	private static SAXParserFactory factory;
 
 	/**
 	 * 禁用默认的DocumentBuilderFactory,禁用后如果有第三方的实现(如oracle的xdb包中的xmlparse),将会自动加载实现。
@@ -185,6 +196,92 @@ public class XmlUtil {
 	}
 
 	/**
+	 * 使用Sax方式读取指定的XML<br>
+	 * 如果用户传入的contentHandler为{@link DefaultHandler},则其接口都会被处理
+	 *
+	 * @param file         XML源文件,使用后自动关闭
+	 * @param contentHandler XML流处理器,用于按照Element处理xml
+	 * @since 5.4.4
+	 */
+	public static void readBySax(File file, ContentHandler contentHandler) {
+		InputStream in = null;
+		try{
+			in = FileUtil.getInputStream(file);
+			readBySax(new InputSource(in), contentHandler);
+		} finally {
+			IoUtil.close(in);
+		}
+	}
+
+	/**
+	 * 使用Sax方式读取指定的XML<br>
+	 * 如果用户传入的contentHandler为{@link DefaultHandler},则其接口都会被处理
+	 *
+	 * @param reader         XML源Reader,使用后自动关闭
+	 * @param contentHandler XML流处理器,用于按照Element处理xml
+	 * @since 5.4.4
+	 */
+	public static void readBySax(Reader reader, ContentHandler contentHandler) {
+		try{
+			readBySax(new InputSource(reader), contentHandler);
+		} finally {
+			IoUtil.close(reader);
+		}
+	}
+
+	/**
+	 * 使用Sax方式读取指定的XML<br>
+	 * 如果用户传入的contentHandler为{@link DefaultHandler},则其接口都会被处理
+	 *
+	 * @param source         XML源流,使用后自动关闭
+	 * @param contentHandler XML流处理器,用于按照Element处理xml
+	 * @since 5.4.4
+	 */
+	public static void readBySax(InputStream source, ContentHandler contentHandler) {
+		try{
+			readBySax(new InputSource(source), contentHandler);
+		} finally {
+			IoUtil.close(source);
+		}
+	}
+
+	/**
+	 * 使用Sax方式读取指定的XML<br>
+	 * 如果用户传入的contentHandler为{@link DefaultHandler},则其接口都会被处理
+	 *
+	 * @param source         XML源,可以是文件、流、路径等
+	 * @param contentHandler XML流处理器,用于按照Element处理xml
+	 * @since 5.4.4
+	 */
+	public static void readBySax(InputSource source, ContentHandler contentHandler) {
+		// 1.获取解析工厂
+		if (null == factory) {
+			factory = SAXParserFactory.newInstance();
+			factory.setValidating(false);
+			factory.setNamespaceAware(namespaceAware);
+		}
+		// 2.从解析工厂获取解析器
+		final SAXParser parse;
+		XMLReader reader;
+		try {
+			parse = factory.newSAXParser();
+			if (contentHandler instanceof DefaultHandler) {
+				parse.parse(source, (DefaultHandler) contentHandler);
+				return;
+			}
+
+			// 3.得到解读器
+			reader = parse.getXMLReader();
+			reader.setContentHandler(contentHandler);
+			reader.parse(source);
+		} catch (ParserConfigurationException | SAXException e) {
+			throw new UtilException(e);
+		} catch (IOException e) {
+			throw new IORuntimeException(e);
+		}
+	}
+
+	/**
 	 * 将String类型的XML转换为XML文档
 	 *
 	 * @param xmlStr XML字符串

+ 15 - 0
hutool-core/src/test/java/cn/hutool/core/util/XmlUtilTest.java

@@ -9,10 +9,13 @@ import org.junit.Assert;
 import org.junit.Ignore;
 import org.junit.Test;
 import org.w3c.dom.Document;
+import org.xml.sax.Attributes;
+import org.xml.sax.helpers.DefaultHandler;
 
 import javax.xml.xpath.XPathConstants;
 import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * {@link XmlUtil} 工具类
@@ -149,6 +152,18 @@ public class XmlUtilTest {
 	}
 
 	@Test
+	public void readBySaxTest(){
+		final Set<String> eles = CollUtil.newHashSet(
+				"returnsms", "returnstatus", "message", "remainpoint", "taskID", "successCounts");
+		XmlUtil.readBySax(ResourceUtil.getStream("test.xml"), new DefaultHandler(){
+			@Override
+			public void startElement(String uri, String localName, String qName, Attributes attributes) {
+				Assert.assertTrue(eles.contains(localName));
+			}
+		});
+	}
+
+	@Test
 	public void mapToXmlTestWithOmitXmlDeclaration() {
 
 		Map<String, Object> map = MapBuilder.create(new LinkedHashMap<String, Object>())