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技术实现该方案

 

  1 package com.juxtapose.xml.parser;
  2 
  3 import java.io.StringReader;
  4 import java.util.ArrayList;
  5 import java.util.HashMap;
  6 import java.util.List;
  7 import java.util.Map;
  8 import java.util.concurrent.atomic.AtomicInteger;
  9 
 10 import javax.xml.stream.XMLInputFactory;
 11 import javax.xml.stream.XMLStreamConstants;
 12 import javax.xml.stream.XMLStreamReader;
 13 
 14 /**
 15  * xml字符串解析器实现类.<br>
 16  * xml字符串转换为Map对象.<br>
 17  * 转换后的数据类型为Map、List、String三种数据类型.<br>
 18  *
 19  * @author burceliu (mailto:jxta.liu@gmail.com)
 20  */
 21 
 22 public class XMLParserStaxImpl implements IXMLParser {
 23     
 24     public static final String NODE_ELEMENT_NAME = "root";
 25     public static final String NODE_DEFAULT_VALUE = "";
 26     
 27     private String rootName;            //根节点
 28     private String defaultNullValue;    //节点没有值的情况下默认值
 29     
 30     private static  XMLInputFactory factory = XMLInputFactory.newInstance(); 
 31     static {
 32         factory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE);
 33         factory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);  
 34     }
 35     
 36     /* (non-Javadoc)
 37      * @see com.juxtapose.xml.parser.IXMLParser#parse(java.lang.String)
 38      */
 39     public Map<String, Object> parse(String xml) {
 40         Map<String, Object> map = new HashMap<String, Object>();
 41         StringReader stringReader = null;
 42         try{
 43             stringReader = new StringReader(xml);
 44             XMLStreamReader reader = factory.createXMLStreamReader(stringReader);  
 45             map = parse(reader);
 46         }catch(Throwable t){
 47             throw new RuntimeException(t);
 48         }finally{
 49             if(null != stringReader){
 50                 try {
 51                     stringReader.close();
 52                 } catch (Exception e) {
 53                     throw new RuntimeException(e);
 54                 }
 55             }
 56         }
 57         return map;
 58     }
 59 
 60     /* (non-Javadoc)
 61      * @see com.juxtapose.xml.parser.IXMLParser#init()
 62      */
 63     public void init() {
 64         if(this.getRootName() == null){
 65             this.setRootName(NODE_ELEMENT_NAME);
 66             this.setDefaultNullValue(NODE_DEFAULT_VALUE);
 67         }
 68     }
 69     
 70     @SuppressWarnings({ "unchecked", "rawtypes" })
 71     private Map<String, Object> parse(XMLStreamReader reader) throws Throwable{
 72         Map<String, Object> map = new HashMap<String, Object>();
 73         Map<String, Object> currentMap = map;
 74         int event = reader.getEventType();
 75         List<String> names = new ArrayList<String>();
 76         NodeAmount nodeAmount = new NodeAmount();
 77         int taglength = 0;
 78         String tagName = null;
 79         String tagValue = this.defaultNullValue;
 80         while(true){
 81             switch (event) {  
 82             case XMLStreamConstants.START_DOCUMENT:
 83                 break;  
 84             case XMLStreamConstants.START_ELEMENT:
 85                 tagValue = this.defaultNullValue;
 86                 tagName = reader.getLocalName();
 87                 if(this.rootName.equals(tagName)){
 88                     break;
 89                 }
 90                 names.add(tagName);
 91                 taglength++;
 92                 
 93                 currentMap = map;
 94                 if(taglength > 1){
 95                     for(int i=0;i< taglength-1;i++){
 96                         Object object = currentMap.get(names.get(i));
 97                         if(null == object){
 98                             object = new HashMap<String, Object>();
 99                             currentMap.put(names.get(i), object);
100                             currentMap = (Map<String, Object>)object;
101                         }else{
102                             int currentTagNameSize = nodeAmount.getSize(i + 1 + "" + names.get(i));
103                             if( currentTagNameSize > 1){
104                                 if(object instanceof Map){
105                                     List parentList = new ArrayList();
106                                     parentList.add(object);
107                                     Map tempMap = new HashMap();
108                                     parentList.add(tempMap);
109                                     currentMap.put(names.get(i), parentList);
110                                     currentMap = tempMap;
111                                 }else if(object instanceof List){
112                                     List parentList = (List)object;
113                                     int parentListSize = parentList.size();
114                                     if(parentListSize != currentTagNameSize){
115                                         Map tempMap = new HashMap();
116                                         parentList.add(tempMap);
117                                         currentMap = tempMap;
118                                     }else{
119                                         Map tempMap = (Map) parentList.get(parentList.size()-1);
120                                         currentMap = tempMap;
121                                     }
122                                 }
123                             }else{
124                                 currentMap = (Map<String, Object>)object;
125                             }
126                         }
127                     }
128                 }
129                 nodeAmount.add(names.size() + tagName);
130                 break;  
131             case XMLStreamConstants.CHARACTERS: 
132                 tagValue = reader.getText();
133                  break;
134             case XMLStreamConstants.END_ELEMENT: 
135                 tagName = reader.getLocalName();
136                 if(this.rootName.equals(tagName)){
137                     break;
138                 }
139                 
140                 currentMap = map;
141                 if(taglength > 1){
142                     for(int i=0;i< taglength-1;i++){
143                         Object object = currentMap.get(names.get(i));
144                         if(null == object){
145                             //nothing to do
146                         }else{
147                             if(object instanceof List){
148                                 List list = (List)object;
149                                 currentMap = (Map)list.get(list.size() -1);
150                             }else if(object instanceof Map){
151                                 currentMap = (Map)object;
152                             }
153                         }
154                     }
155                 }
156                 
157                 Object oldValue = currentMap.get(tagName);
158                 if(!currentMap.containsKey(tagName)){
159                     currentMap.put(tagName, tagValue);
160                     nodeAmount.remove(names.size() + tagName);
161                 }else{
162                     if(oldValue instanceof List){
163                         List list = (List)oldValue;
164                         if(list.size() > 0){
165                             Object obj = list.get(0);
166                             if(obj instanceof String){
167                                 ((List)oldValue).add(tagValue);
168                                 nodeAmount.remove(names.size() + tagName);
169                             }
170                         }
171                     }else if(oldValue instanceof Map){
172                         
173                     }else{
174                         List tmpList = new ArrayList();
175                         currentMap.put(tagName, tmpList);
176                         tmpList.add(oldValue);
177                         tmpList.add(tagValue);
178                         nodeAmount.remove(names.size() + tagName);
179                     }
180                 }
181                 
182                 tagValue = this.defaultNullValue;
183                 names.remove(names.size()-1);
184                 taglength--;
185                 break;  
186             case XMLStreamConstants.END_DOCUMENT:  
187                 break;  
188             }  
189 
190             if (!reader.hasNext()) {  
191                 break;  
192             }  
193             event = reader.next();  
194         }
195         return map;
196     }
197 
198     public String getRootName() {
199         return rootName;
200     }
201 
202     public void setRootName(String rootName) {
203         this.rootName = rootName;
204     }
205 
206     public String getDefaultNullValue() {
207         return defaultNullValue;
208     }
209 
210     public void setDefaultNullValue(String defaultNullValue) {
211         this.defaultNullValue = defaultNullValue;
212     }
213     
214     class NodeAmount{
215         private Map<String, AtomicInteger> map =new HashMap<String, AtomicInteger>();
216         
217         public void add(String nodeName){
218             AtomicInteger integer = map.get(nodeName);
219             if(null == integer){
220                 integer = new AtomicInteger(0);
221                 map.put(nodeName, integer);
222             }
223             integer.incrementAndGet();
224         }
225         
226         public void remove(String nodeName){
227             AtomicInteger integer = map.get(nodeName);
228             if(null != integer){
229                 integer.decrementAndGet();
230             }
231         }
232         
233         public int getSize(String nodeName){
234             AtomicInteger integer = map.get(nodeName);
235             if(null == integer){
236                 integer = new AtomicInteger(0);
237                 map.put(nodeName, integer);
238             }
239             return integer.intValue();
240         }
241     }
242 
243 }
244 
245 /*
246  * 修改历史
247  * $Log$ 
248  */

3、单元测试

 1 package test.com.juxtapose.xml.parser;
 2 
 3 import java.util.Map;
 4 
 5 import org.junit.After;
 6 import org.junit.AfterClass;
 7 import org.junit.Before;
 8 import org.junit.BeforeClass;
 9 import org.junit.Test;
10 
11 import com.juxtapose.xml.parser.IXMLParser;
12 import com.juxtapose.xml.parser.XMLParserStaxImpl;
13 
14 /**
15  *
16  * @author burceliu (mailto:jxta.liu@gmail.com)
17  */
18 
19 public class TestXMLParserStaxImpl {
20 
21     /**
22      * @throws java.lang.Exception
23      */
24     @BeforeClass
25     public static void setUpBeforeClass() throws Exception {
26     }
27 
28     /**
29      * @throws java.lang.Exception
30      */
31     @AfterClass
32     public static void tearDownAfterClass() throws Exception {
33     }
34 
35     /**
36      * @throws java.lang.Exception
37      */
38     @Before
39     public void setUp() throws Exception {
40     }
41 
42     /**
43      * @throws java.lang.Exception
44      */
45     @After
46     public void tearDown() throws Exception {
47     }
48 
49     @Test
50     public void test() {
51         IXMLParser parser =  new XMLParserStaxImpl();
52         parser.init();
53         String xml = "<root><student><name>BurceLiu</name><age>18</age></student></root>";
54         Map<String, Object> result = parser.parse(xml);
55         System.out.println(result);
56         xml = "<root><student><name>BurceLiu</name><age>18</age></student><student><name>BurceLi</name><age>28</age></student></root>";
57         result = parser.parse(xml);
58         System.out.println(result);
59         xml = "<root><str>str1</str><str>str2</str><str>str3</str></root>";
60         result = parser.parse(xml);
61         System.out.println(result);
62         xml = "<root><students><student><name>BurceLiu</name><age>18</age></student><student><name>BurceLi</name><age>28</age></student></students></root>";
63         result = parser.parse(xml);
64         System.out.println(result);
65         xml = "<root><name>BurceLiu</name><age>18</age></root>";
66         result = parser.parse(xml);
67         System.out.println(result);
68     }
69 
70 }
71 
72 /*
73  * 修改历史
74  * $Log$ 
75  */

 

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与我取得联系。

 

posted on 2015-02-10 10:03  juxtapose  阅读(907)  评论(0编辑  收藏  举报

导航