数据结构|XML转换为Map通用算法实现(Stax实现)

目前项目中需要将XML转换为Map,下面给出了自己的代码实现。请各路大神提供更好的代码实现。
场景:
在项目中需要解析XML文本字符串,需要将XML文本字符串映射为Map格式的对象。
需求:
1、为了提高性能,需要使用Stax进行解析
2、Map结构内部需要支持List、Map、String三种数据格式
示例:

例一: *字符串:BurceLiu18 *转换为的Map结构:{age=18, name=BurceLiu}

例二: *字符串:BurceLiu18 *转换为的Map结构:{student={age=18, name=BurceLiu}}


例三: *字符串:BurceLiu18BurceLi28 *转换为的Map结构:{student=[{age=18, name=BurceLiu}, {age=28, name=BurceLi}]}


例四: *字符串:BurceLiu18BurceLi28 *转换为的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 = "BurceLiu18"; Map result = parser.parse(xml); System.out.println(result); xml = "BurceLiu18BurceLi28"; result = parser.parse(xml); System.out.println(result); xml = "str1str2str3"; result = parser.parse(xml); System.out.println(result); xml = "BurceLiu18BurceLi28"; result = parser.parse(xml); System.out.println(result); xml = "BurceLiu18"; 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}




    推荐阅读