目前项目中需要将XML转换为Map,下面给出了自己的代码实现。请各路大神提供更好的代码实现。
场景:
在项目中需要解析XML文本字符串,需要将XML文本字符串映射为Map格式的对象。
需求:
1、为了提高性能,需要使用Stax进行解析
2、Map结构内部需要支持List、Map、String三种数据格式
示例:
例一: * 字符串:<name>BurceLiu</name><age>18</age> * 转换为的Map结构:{age=18, name=BurceLiu}
例二: * 字符串:<student><name>BurceLiu</name><age>18</age></student> * 转换为的Map结构:{student={age=18, name=BurceLiu}}
例三: * 字符串:<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}]}
例四: * 字符串:<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}]}}
例五: * 字符串:<str>str1</str><str>str2</str><str>str3</str> * 转换为的Map结构:{str=[str1, str2, str3]}
代码实现
定义解析接口,提供2个核心方法
public interface IXMLParser { /** * xml格式字符串转换为Map * @param xml * @return */ public Map<String, Object> 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字符串解析器实现类.<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$ */
单元测试:
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$ */
观察控制台的输出结果:
{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}
原文:http://www.cnblogs.com/jxta/p/4283107.html