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:[email protected]) */ 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 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 = 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 = 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 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:[email protected])
 */

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$ 
 */

观察控制台的输出结果:

{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)