XML转换为Map通用算法实现 Java版本(Stax实现)
目前项目中需要将XML转换为Map,下面给出了自己的代码实现。
后续将为大家提供Dom版本的实现。
请各路大神给予各种优良实现。
场景:
在项目中需要解析XML文本字符串,需要将XML文本字符串映射为Map格式的对象。
需求:
1、为了提高性能,需要使用Stax进行解析
2、Map结构内部需要支持List、Map、String三种数据格式
示例:
例一:字符串直接转换为Map结构
* 字符串:<name>BurceLiu</name><age>18</age>
* 转换为的Map结构:{age=18, name=BurceLiu}
例二:字符串转换为Map结构,Map内部嵌套Map的结构
* 字符串:<student><name>BurceLiu</name><age>18</age></student>
* 转换为的Map结构:{student={age=18, name=BurceLiu}}
例三:字符串转换为Map结构,Map内部嵌套为List的结构,List内部为Map
* 字符串:<student><name>BurceLiu</name><age>18</age></student><student><name>BurceLi</name><age>28</age></student>
* 转换为的Map结构:{student=[{age=18, name=BurceLiu}, {age=28, name=BurceLi}]}
例四:字符串转换为Map结构,Map内部嵌套Map,Map内部嵌套List
* 字符串:<students><student><name>BurceLiu</name><age>18</age></student><student><name>BurceLi</name><age>28</age></student></students>
* 转换为的Map结构:{students={student=[{age=18, name=BurceLiu}, {age=28, name=BurceLi}]}}
例五:字符串转换为List结构
* 字符串:<str>str1</str><str>str2</str><str>str3</str>
* 转换为的Map结构:{str=[str1, str2, str3]}
代码实现
1、接口定义
定义解析接口,提供2个核心方法
public interface IXMLParser { /**
* xml格式字符串转换为Map
* @param xml
* @return
*/
public Map<String, Object> parse(String xml); /**
* 初始化动作
* 可以设置初始化动作,例如根节点名称,
*/
public void init();
}
2、实现类
具体实现类,采用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字符串解析器实现类.<br>
* xml字符串转换为Map对象.<br>
* 转换后的数据类型为Map、List、String三种数据类型.<br>
*
* @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_VALUE = ""; private String rootName; //根节点
private String defaultNullValue; //节点没有值的情况下默认值 private static XMLInputFactory 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<String, Object> parse(String xml) {
Map<String, Object> map = new HashMap<String, Object>();
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<String, Object> parse(XMLStreamReader reader) throws Throwable{
Map<String, Object> map = new HashMap<String, Object>();
Map<String, Object> currentMap = map;
int event = reader.getEventType();
List<String> names = new ArrayList<String>();
NodeAmount nodeAmount = new NodeAmount();
int taglength = 0;
String tagName = null;
String tagValue = 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<String, Object>();
currentMap.put(names.get(i), object);
currentMap = (Map<String, Object>)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<String, Object>)object;
}
}
}
}
nodeAmount.add(names.size() + tagName);
break;
case XMLStreamConstants.CHARACTERS:
tagValue = 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 = 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 = 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<String, AtomicInteger> map =new HashMap<String, AtomicInteger>(); 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$
*/
3、单元测试
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 = "<root><student><name>BurceLiu</name><age>18</age></student></root>";
Map<String, Object> result = parser.parse(xml);
System.out.println(result);
xml = "<root><student><name>BurceLiu</name><age>18</age></student><student><name>BurceLi</name><age>28</age></student></root>";
result = parser.parse(xml);
System.out.println(result);
xml = "<root><str>str1</str><str>str2</str><str>str3</str></root>";
result = parser.parse(xml);
System.out.println(result);
xml = "<root><students><student><name>BurceLiu</name><age>18</age></student><student><name>BurceLi</name><age>28</age></student></students></root>";
result = parser.parse(xml);
System.out.println(result);
xml = "<root><name>BurceLiu</name><age>18</age></root>";
result = parser.parse(xml);
System.out.println(result);
} } /*
* 修改历史
* $Log$
*/
4、测试结果
观察控制台的输出结果:
{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}
如有任何问题,可以通过jxta.liu@gmail.com与我取得联系。
XML转换为Map通用算法实现 Java版本(Stax实现)的更多相关文章
- 使用 Dom4j 将 XML 转换为 MAP
本文为转载:http://blog.sina.com.cn/s/blog_6145ed810100z164.html 原文地址. 自己仅作备忘录方便查找留了一份. 这是解析Xml 的辅助类 pack ...
- 基础算法(java版本)
Practice Author: Dorae Date: 2018年10月11日13:57:44 转载请注明出处 具体代码请移步git 基础算法 图 Prim Kruskal Dijkstra Flo ...
- 数据结构和算法(java版本)学习指南
1 数据结构和算法内容介绍 2 数据结构和算法的概述 3 稀疏数组SparseArray
- Java的xml与map,与Bean互转
xml与map互转,主要使用dom4j import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j. ...
- xml转Map,对象,Map转xml,inputs tram 转xml 字符串的工具类方法
众所周知,大家在微信开发工程中,由于微信开发文档中,对于消息的接收发送都是基础xml数据的(太坑了),所以我们需要对XML进行解析转换: 1.我们先引入所需要的依赖 dom4j (解析xml的),xs ...
- Xml与Map之间的相互转换
一.(单层)xml转换为map /** * XML格式字符串转换为Map * * @param xml XML字符串 * @return XML数据转换后的Map * @throws Exceptio ...
- Java版本:识别Json字符串并分隔成Map集合
前言: 最近又看了点Java的知识,于是想着把CYQ.Data V5迁移到Java版本. 过程发现坑很多,理论上看大部分很相似,实践上代码写起来发现大部分都要重新思考方案. 遇到的C#转Java的一些 ...
- Bean-Query 一个把对象转换为Map的Java工具库
刚开源了一个经过完整測试的Java工具类. 地址例如以下: https://github.com/Jimmy-Shi/bean-query 使用说明例如以下: Bean-query Click Her ...
- Java工具类——通过配置XML验证Map
Java工具类--通过配置XML验证Map 背景 在JavaWeb项目中,接收前端过来的参数时通常是使用我们的实体类进行接收的.但是呢,我们不能去决定已经搭建好的框架是怎么样的,在我接触的框架中有一种 ...
随机推荐
- Ubuntu 14.04怎样升级到Ubuntu 14.10
Ubuntu 14.04怎样升级到Ubuntu 14.10 Ubuntu 14.10 Utopic Unicorn 将在10月23日正式发布,9月25日最终测试版本已经发布,Ubuntu 14 ...
- Eclipse 下如何删除一个项目的 SVN 信息
选中项目,右键 - Team - 断开连接 出现如下对话框,根据需要,选择 “删除”或者“不删除”,点击 Yes 即可
- iPhone —— 如何自制铃声(图文)
iPhone不像其他手机可以直接将MP3格式的文件设为铃声.但如果想用自己喜欢的歌曲作为铃声该怎么办呢?请听我一一道来. 一.将MP3文件转换成iPhone铃声能识别的M4R格式文件 1.向iTune ...
- ccnu-线段树-单点更新3-C
C - 单点更新3 Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Submit Status Des ...
- 利用SOLR搭建企业搜索平台 之——模式配置Schema.xml
来源:http://blog.csdn.net/awj3584/article/details/16963525 schema.xml这个配置文件可以在你下载solr包的安装解压目录的\solr\ex ...
- leetcode:Contains Duplicate和Contains Duplicate II
一.Contains Duplicate Given an array of integers, find if the array contains any duplicates. Your fun ...
- 非常非常非常好!path-sum-iii
https://leetcode.com/problems/path-sum-iii/ 最终我还是没做出好的解法.还是看的别人的解法. 即使看了别人的解法,开始还实现错了. 还有很长的路要走. pac ...
- STM32-F0/F1/F2
用到的资源是:A.ST公司提供:STM32F10x开发标准库V3.5B.实验平台:战舰开发板V2.1C.编译软件:MDK3.8D.编辑软件:Source Insight_V3.5E.RTOS:ucos ...
- PDO防注入原理分析以及使用PDO的注意事项 (转)
我们都知道,只要合理正确使用PDO,可以基本上防止SQL注入的产生,本文主要回答以下两个问题: 为什么要使用PDO而不是mysql_connect? 为何PDO能防注入? 使用PDO防注入的时候应该特 ...
- C的结构体使用
C的结构体演示 #include <stdio.h> struct A //建立结构体A { char *name; int s1; struct A *next; }; void mai ...