mirror of
https://gitee.com/dromara/hutool.git
synced 2025-04-05 17:37:59 +08:00
XmlUtil.mapToXml support List
This commit is contained in:
parent
4210ebaa4e
commit
ced42166d3
@ -20,6 +20,7 @@
|
||||
* 【core 】 添加ValidateObjectInputStream避免对象反序列化漏洞风险
|
||||
* 【core 】 添加BiMap
|
||||
* 【all 】 cn.hutool.extra.servlet.multipart包迁移到cn.hutool.core.net下
|
||||
* 【core 】 XmlUtil.mapToXml方法支持集合解析(issue#820@Github)
|
||||
|
||||
### Bug修复
|
||||
* 【extra 】 修复SpringUtil使用devtools重启报错问题
|
||||
|
@ -15,6 +15,31 @@ public class MapBuilder<K, V> implements Serializable{
|
||||
|
||||
private Map<K, V> map;
|
||||
|
||||
/**
|
||||
* 创建Builder,默认HashMap实现
|
||||
*
|
||||
* @param <K> Key类型
|
||||
* @param <V> Value类型
|
||||
* @return MapBuilder
|
||||
* @since 5.3.0
|
||||
*/
|
||||
public static <K, V> MapBuilder<K, V> create() {
|
||||
return create(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建Builder
|
||||
*
|
||||
* @param <K> Key类型
|
||||
* @param <V> Value类型
|
||||
* @param isLinked true创建LinkedHashMap,false创建HashMap
|
||||
* @return MapBuilder
|
||||
* @since 5.3.0
|
||||
*/
|
||||
public static <K, V> MapBuilder<K, V> create(boolean isLinked) {
|
||||
return create(MapUtil.newHashMap(isLinked));
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建Builder
|
||||
*
|
||||
|
@ -17,7 +17,11 @@ import javax.xml.namespace.QName;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.*;
|
||||
import javax.xml.transform.OutputKeys;
|
||||
import javax.xml.transform.Result;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.xpath.XPath;
|
||||
@ -26,12 +30,20 @@ import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
import java.beans.XMLDecoder;
|
||||
import java.beans.XMLEncoder;
|
||||
import java.io.*;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* XML工具类<br>
|
||||
@ -519,6 +531,16 @@ public class XmlUtil {
|
||||
return (null == doc) ? null : doc.getDocumentElement();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取节点所在的Document
|
||||
* @param node 节点
|
||||
* @return {@link Document}
|
||||
* @since 5.3.0
|
||||
*/
|
||||
public static Document getOwnerDocument(Node node){
|
||||
return (node instanceof Document) ? (Document) node : node.getOwnerDocument();
|
||||
}
|
||||
|
||||
/**
|
||||
* 去除XML文本中的无效字符
|
||||
*
|
||||
@ -956,7 +978,6 @@ public class XmlUtil {
|
||||
* @since 4.0.9
|
||||
*/
|
||||
public static Document mapToXml(Map<?, ?> data, String rootName) {
|
||||
|
||||
return mapToXml(data, rootName, null);
|
||||
}
|
||||
|
||||
@ -973,7 +994,7 @@ public class XmlUtil {
|
||||
final Document doc = createXml();
|
||||
final Element root = appendChild(doc, rootName, namespace);
|
||||
|
||||
mapToXml(doc, root, data);
|
||||
appendMap(doc, root, data);
|
||||
return doc;
|
||||
}
|
||||
|
||||
@ -1025,59 +1046,106 @@ public class XmlUtil {
|
||||
* @since 5.0.4
|
||||
*/
|
||||
public static Element appendChild(Node node, String tagName, String namespace) {
|
||||
final Document doc = (node instanceof Document) ? (Document) node : node.getOwnerDocument();
|
||||
final Document doc = getOwnerDocument(node);
|
||||
final Element child = (null == namespace) ? doc.createElement(tagName) : doc.createElementNS(namespace, tagName);
|
||||
node.appendChild(child);
|
||||
return child;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建文本子节点
|
||||
*
|
||||
* @param node 节点
|
||||
* @param text 文本
|
||||
* @return 子节点
|
||||
* @since 5.3.0
|
||||
*/
|
||||
public static Node appendText(Node node, CharSequence text){
|
||||
return appendText(getOwnerDocument(node), node, text);
|
||||
}
|
||||
// ---------------------------------------------------------------------------------------- Private method start
|
||||
|
||||
/**
|
||||
* 将Map转换为XML格式的字符串
|
||||
* 追加数据子节点,可以是Map、集合、文本
|
||||
*
|
||||
* @param doc {@link Document}
|
||||
* @param node 节点
|
||||
* @param data 数据
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static void append(Document doc, Node node, Object data){
|
||||
if (data instanceof Map) {
|
||||
// 如果值依旧为map,递归继续
|
||||
appendMap(doc, node, (Map) data);
|
||||
} else if (data instanceof Iterator) {
|
||||
// 如果值依旧为map,递归继续
|
||||
appendIterator(doc, node, (Iterator) data);
|
||||
}else if (data instanceof Iterable) {
|
||||
// 如果值依旧为map,递归继续
|
||||
appendIterator(doc, node, ((Iterable)data).iterator());
|
||||
} else {
|
||||
appendText(doc, node, data.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加Map数据子节点
|
||||
*
|
||||
* @param doc {@link Document}
|
||||
* @param element 节点
|
||||
* @param node 当前节点
|
||||
* @param data Map类型数据
|
||||
* @since 4.0.8
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static void mapToXml(Document doc, Element element, Map<?, ?> data) {
|
||||
Element filedEle;
|
||||
Object key;
|
||||
for (Entry<?, ?> entry : data.entrySet()) {
|
||||
key = entry.getKey();
|
||||
if (null == key) {
|
||||
continue;
|
||||
}
|
||||
// key作为标签名,无值的节点作为空节点创建
|
||||
filedEle = doc.createElement(key.toString());
|
||||
element.appendChild(filedEle);
|
||||
// value作为标签内的值。
|
||||
final Object value = entry.getValue();
|
||||
if (null == value) {
|
||||
continue;
|
||||
}
|
||||
if (value instanceof List) {
|
||||
for (Object listEle : (List) value) {
|
||||
if (listEle instanceof Map) {
|
||||
// 如果值依旧为map,递归继续
|
||||
mapToXml(doc, filedEle, (Map<?, ?>) listEle);
|
||||
} else {
|
||||
// 创建文本节点
|
||||
filedEle.appendChild(doc.createTextNode(value.toString()));
|
||||
}
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private static void appendMap(Document doc, Node node, Map data) {
|
||||
data.forEach((key, value)->{
|
||||
if(null != key){
|
||||
final Element child = appendChild(node, key.toString());
|
||||
if(null != value){
|
||||
append(doc, child, value);
|
||||
}
|
||||
} else if (value instanceof Map) {
|
||||
// 如果值依旧为map,递归继续
|
||||
mapToXml(doc, filedEle, (Map<?, ?>) value);
|
||||
} else {
|
||||
filedEle.appendChild(doc.createTextNode(value.toString()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加集合节点
|
||||
*
|
||||
* @param doc {@link Document}
|
||||
* @param node 节点
|
||||
* @param data 数据
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static void appendIterator(Document doc, Node node, Iterator data){
|
||||
final Node parentNode = node.getParentNode();
|
||||
boolean isFirst = true;
|
||||
Object eleData;
|
||||
while(data.hasNext()){
|
||||
eleData = data.next();
|
||||
if(isFirst){
|
||||
append(doc, node, eleData);
|
||||
isFirst = false;
|
||||
} else{
|
||||
final Node cloneNode = node.cloneNode(false);
|
||||
parentNode.appendChild(cloneNode);
|
||||
append(doc, cloneNode, eleData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加文本节点
|
||||
*
|
||||
* @param doc {@link Document}
|
||||
* @param node 节点
|
||||
* @param text 文本内容
|
||||
* @return 增加的子节点,即Text节点
|
||||
* @since 5.3.0
|
||||
*/
|
||||
private static Node appendText(Document doc, Node node, CharSequence text){
|
||||
return node.appendChild(doc.createTextNode(StrUtil.str(text)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭XXE,避免漏洞攻击<br>
|
||||
* see: https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#JAXP_DocumentBuilderFactory.2C_SAXParserFactory_and_DOM4J
|
||||
|
@ -14,12 +14,11 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* {@link XmlUtil} 工具类
|
||||
*
|
||||
* @author Looly
|
||||
*
|
||||
* @author Looly
|
||||
*/
|
||||
public class XmlUtilTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void parseTest() {
|
||||
String result = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"//
|
||||
@ -84,7 +83,7 @@ public class XmlUtilTest {
|
||||
Assert.assertEquals("1490", map.get("remainpoint"));
|
||||
Assert.assertEquals("885", map.get("taskID"));
|
||||
Assert.assertEquals("1", map.get("successCounts"));
|
||||
Assert.assertEquals("subText", ((Map<?, ?>)map.get("newNode")).get("sub"));
|
||||
Assert.assertEquals("subText", ((Map<?, ?>) map.get("newNode")).get("sub"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -106,17 +105,33 @@ public class XmlUtilTest {
|
||||
Document doc = XmlUtil.mapToXml(map, "user");
|
||||
// Console.log(XmlUtil.toStr(doc, false));
|
||||
Assert.assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"//
|
||||
+ "<user>"//
|
||||
+ "<name>张三</name>"//
|
||||
+ "<age>12</age>"//
|
||||
+ "<game>"//
|
||||
+ "<昵称>Looly</昵称>"//
|
||||
+ "<level>14</level>"//
|
||||
+ "</game>"//
|
||||
+ "</user>", //
|
||||
+ "<user>"//
|
||||
+ "<name>张三</name>"//
|
||||
+ "<age>12</age>"//
|
||||
+ "<game>"//
|
||||
+ "<昵称>Looly</昵称>"//
|
||||
+ "<level>14</level>"//
|
||||
+ "</game>"//
|
||||
+ "</user>", //
|
||||
XmlUtil.toStr(doc, false));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void mapToXmlTest2() {
|
||||
// 测试List
|
||||
Map<String, Object> map = MapBuilder.create(new LinkedHashMap<String, Object>())
|
||||
.put("Town", CollUtil.newArrayList("town1", "town2"))
|
||||
.build();
|
||||
|
||||
Document doc = XmlUtil.mapToXml(map, "City");
|
||||
Assert.assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>" +
|
||||
"<City>" +
|
||||
"<Town>town1</Town>" +
|
||||
"<Town>town2</Town>" +
|
||||
"</City>",
|
||||
XmlUtil.toStr(doc));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readTest() {
|
||||
Document doc = XmlUtil.readXML("test.xml");
|
||||
@ -127,9 +142,9 @@ public class XmlUtilTest {
|
||||
public void mapToXmlTestWithOmitXmlDeclaration() {
|
||||
|
||||
Map<String, Object> map = MapBuilder.create(new LinkedHashMap<String, Object>())
|
||||
.put("name", "ddatsh")
|
||||
.build();
|
||||
String xml=XmlUtil.mapToXmlStr(map,true);
|
||||
Assert.assertEquals(xml,"<xml><name>ddatsh</name></xml>");
|
||||
}
|
||||
.put("name", "ddatsh")
|
||||
.build();
|
||||
String xml = XmlUtil.mapToXmlStr(map, true);
|
||||
Assert.assertEquals("<xml><name>ddatsh</name></xml>", xml);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user