目前项目中需要将XML转换为Map,下面给出了自己的代码实现。请各路大神提供更好的代码实现。
场景:
在项目中需要解析XML文本字符串,需要将XML文本字符串映射为Map格式的对象。
需求:
1、为了提高性能,需要使用Stax进行解析
2、Map结构内部需要支持List、Map、String三种数据格式
示例:
例一:
*字符串:BurceLiu 18
*转换为的Map结构:{age=18, name=BurceLiu}
例二:
*字符串:BurceLiu 18
*转换为的Map结构:{student={age=18, name=BurceLiu}}
例三:
*字符串:BurceLiu 18BurceLi 28
*转换为的Map结构:{student=[{age=18, name=BurceLiu}, {age=28, name=BurceLi}]}
例四:
*字符串:BurceLiu 18BurceLi 28
*转换为的Map结构:{students={student=[{age=18, name=BurceLiu}, {age=28, name=BurceLi}]}}
例五:
*字符串:str1str2str3
*转换为的Map结构:{str=[str1, str2, str3]}
代码实现
定义解析接口,提供2个核心方法
public interface IXMLParser {
/**
* xml格式字符串转换为Map
* @param xml
* @return
*/
public Map parse(String xml);
/**
* 初始化动作
* 可以设置初始化动作,例如根节点名称,
*/
public void init();
}
具体实现类,采用Stax技术实现该方案
package com.juxtapose.xml.parser;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;
/**
* xml字符串解析器实现类.
* xml字符串转换为Map对象.
* 转换后的数据类型为Map、List、String三种数据类型.
*
* @author burceliu (mailto:jxta.liu@gmail.com)
*/public class XMLParserStaxImpl implements IXMLParser {
public static final String NODE_ELEMENT_NAME = "root";
public static final String NODE_DEFAULT_VALUEhttps://www.it610.com/article/= "";
private String rootName;
//根节点
private String defaultNullValue;
//节点没有值的情况下默认值
private staticXMLInputFactory factory = XMLInputFactory.newInstance();
static {
factory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE);
factory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
}
/* (non-Javadoc)
* @see com.juxtapose.xml.parser.IXMLParser#parse(java.lang.String)
*/
public Map parse(String xml) {
Map map = new HashMap();
StringReader stringReader = null;
try{
stringReader = new StringReader(xml);
XMLStreamReader reader = factory.createXMLStreamReader(stringReader);
map = parse(reader);
}catch(Throwable t){
throw new RuntimeException(t);
}finally{
if(null != stringReader){
try {
stringReader.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
return map;
} /* (non-Javadoc)
* @see com.juxtapose.xml.parser.IXMLParser#init()
*/
public void init() {
if(this.getRootName() == null){
this.setRootName(NODE_ELEMENT_NAME);
this.setDefaultNullValue(NODE_DEFAULT_VALUE);
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private Map parse(XMLStreamReader reader) throws Throwable{
Map map = new HashMap();
Map currentMap = map;
int event = reader.getEventType();
List names = new ArrayList();
NodeAmount nodeAmount = new NodeAmount();
int taglength = 0;
String tagName = null;
String tagValue = https://www.it610.com/article/this.defaultNullValue;
while(true){
switch (event) {
case XMLStreamConstants.START_DOCUMENT:
break;
case XMLStreamConstants.START_ELEMENT:
tagValue = this.defaultNullValue;
tagName = reader.getLocalName();
if(this.rootName.equals(tagName)){
break;
}
names.add(tagName);
taglength++;
currentMap = map;
if(taglength> 1){
for(int i=0;
i< taglength-1;
i++){
Object object = currentMap.get(names.get(i));
if(null == object){
object = new HashMap();
currentMap.put(names.get(i), object);
currentMap = (Map)object;
}else{
int currentTagNameSize = nodeAmount.getSize(i + 1 + "" + names.get(i));
if( currentTagNameSize > 1){
if(object instanceof Map){
List parentList = new ArrayList();
parentList.add(object);
Map tempMap = new HashMap();
parentList.add(tempMap);
currentMap.put(names.get(i), parentList);
currentMap = tempMap;
}else if(object instanceof List){
List parentList = (List)object;
int parentListSize = parentList.size();
if(parentListSize != currentTagNameSize){
Map tempMap = new HashMap();
parentList.add(tempMap);
currentMap = tempMap;
}else{
Map tempMap = (Map) parentList.get(parentList.size()-1);
currentMap = tempMap;
}
}
}else{
currentMap = (Map)object;
}
}
}
}
nodeAmount.add(names.size() + tagName);
break;
case XMLStreamConstants.CHARACTERS:
tagValue = https://www.it610.com/article/reader.getText();
break;
case XMLStreamConstants.END_ELEMENT:
tagName = reader.getLocalName();
if(this.rootName.equals(tagName)){
break;
}currentMap = map;
if(taglength> 1){
for(int i=0;
i< taglength-1;
i++){
Object object = currentMap.get(names.get(i));
if(null == object){
//nothing to do
}else{
if(object instanceof List){
List list = (List)object;
currentMap = (Map)list.get(list.size() -1);
}else if(object instanceof Map){
currentMap = (Map)object;
}
}
}
}Object oldValue = https://www.it610.com/article/currentMap.get(tagName);
if(!currentMap.containsKey(tagName)){
currentMap.put(tagName, tagValue);
nodeAmount.remove(names.size() + tagName);
}else{
if(oldValue instanceof List){
List list = (List)oldValue;
if(list.size()> 0){
Object obj = list.get(0);
if(obj instanceof String){
((List)oldValue).add(tagValue);
nodeAmount.remove(names.size() + tagName);
}
}
}else if(oldValue instanceof Map){}else{
List tmpList = new ArrayList();
currentMap.put(tagName, tmpList);
tmpList.add(oldValue);
tmpList.add(tagValue);
nodeAmount.remove(names.size() + tagName);
}
}tagValue = https://www.it610.com/article/this.defaultNullValue;
names.remove(names.size()-1);
taglength--;
break;
case XMLStreamConstants.END_DOCUMENT:
break;
}if (!reader.hasNext()) {
break;
}
event = reader.next();
}
return map;
} public String getRootName() {
return rootName;
} public void setRootName(String rootName) {
this.rootName = rootName;
} public String getDefaultNullValue() {
return defaultNullValue;
} public void setDefaultNullValue(String defaultNullValue) {
this.defaultNullValue = defaultNullValue;
}
class NodeAmount{
private Map map =new HashMap();
public void add(String nodeName){
AtomicInteger integer = map.get(nodeName);
if(null == integer){
integer = new AtomicInteger(0);
map.put(nodeName, integer);
}
integer.incrementAndGet();
}public void remove(String nodeName){
AtomicInteger integer = map.get(nodeName);
if(null != integer){
integer.decrementAndGet();
}
}public int getSize(String nodeName){
AtomicInteger integer = map.get(nodeName);
if(null == integer){
integer = new AtomicInteger(0);
map.put(nodeName, integer);
}
return integer.intValue();
}
}}/*
* 修改历史
* $Log$
*/
单元测试:
package test.com.juxtapose.xml.parser;
import java.util.Map;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import com.juxtapose.xml.parser.IXMLParser;
import com.juxtapose.xml.parser.XMLParserStaxImpl;
/**
*
* @author burceliu (mailto:jxta.liu@gmail.com)
*/public class TestXMLParserStaxImpl { /**
* @throws java.lang.Exception
*/
@BeforeClass
public static void setUpBeforeClass() throws Exception {
} /**
* @throws java.lang.Exception
*/
@AfterClass
public static void tearDownAfterClass() throws Exception {
} /**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
} /**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {
} @Test
public void test() {
IXMLParser parser =new XMLParserStaxImpl();
parser.init();
String xml = "BurceLiu 18 ";
Map result = parser.parse(xml);
System.out.println(result);
xml = "BurceLiu 18BurceLi 28 ";
result = parser.parse(xml);
System.out.println(result);
xml = "str1str2str3 ";
result = parser.parse(xml);
System.out.println(result);
xml = "BurceLiu 18BurceLi 28 ";
result = parser.parse(xml);
System.out.println(result);
xml = "BurceLiu 18 ";
result = parser.parse(xml);
System.out.println(result);
}}/*
* 修改历史
* $Log$
*/
观察控制台的输出结果: 【数据结构|XML转换为Map通用算法实现(Stax实现)】
{student={age=18, name=BurceLiu}}
{student=[{age=18, name=BurceLiu}, {age=28, name=BurceLi}]}
{str=[str1, str2, str3]}
{students={student=[{age=18, name=BurceLiu}, {age=28, name=BurceLi}]}}
{age=18, name=BurceLiu}
推荐阅读
- Java|Java基础——数组
- 人工智能|干货!人体姿态估计与运动预测
- java简介|Java是什么(Java能用来干什么?)
- Java|规范的打印日志
- Linux|109 个实用 shell 脚本
- 程序员|【高级Java架构师系统学习】毕业一年萌新的Java大厂面经,最新整理
- Spring注解驱动第十讲--@Autowired使用
- SqlServer|sql server的UPDLOCK、HOLDLOCK试验
- jvm|【JVM】JVM08(java内存模型解析[JMM])
- 技术|为参加2021年蓝桥杯Java软件开发大学B组细心整理常见基础知识、搜索和常用算法解析例题(持续更新...)