目前项目中需要将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]}
定义解析接口,提供2个核心方法
public interface IXMLParser { /** * xml格式字符串转换为Map * @param xml * @return */ public Map<String, Object> parse(String xml); /** * 初始化动作 * 可以设置初始化动作,例如根节点名称, */ public void init(); }
具体实现类,采用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:[email protected]) 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 */
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:[email protected]) 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 */
观察控制台的输出结果:
{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}
如有任何问题,可以通过[email protected]与我取得联系。