2014-03-06 50 views
1

我有一個帶有嵌套元素和重複標籤的XML。例如:將XML轉換爲嵌套地圖的地圖

<person> 
    <name>Rama</name> 
    <age>27</age> 
    <gender>male</gender> 
    <address> 
     <doornumber>234</doornumber> 
     <street>Kanon</street> 
     <city>Hyderabad</city> 
    </address> 
    <qualification> 
     <degree>M.Sc</degree> 
     <specialisation>Maths</specialisation> 
    </qualification> 
    <qualification> 
     <degree>B.E.</degree> 
     <specialisation>Electrical</specialisation> 
    </qualification> 
</person> 

現在我想的API,將這個XML轉換成一個Map地圖在Java中:

{name="Rama",age="27",gender="male",address={doornumber=234,street="Kanon",city="Hyderabad"},qualification=[{degree="M.Sc",specialisation="Maths"},{degree="B.E.",specialisation="Electrical"}]} 

我知道,我們可以使用XStream API把實現這一目標。這裏我只想知道使用XStream是否有缺點,以及是否存在其他更好的Java API來實現這一點。有什麼建議麼?

注意:這應該以通用方式完成,即Java API應該適用於任何XML,而不僅僅適用於上述XML。

+0

嘿,如果API爲你工作,使用它,也可能最終會主要是基於意見。 –

回答

0

就個人而言,我會使用標準的JAXP接口 - SAX如果你真的想要地圖的地圖,如果你想保持順序(樹而不是無序的嵌套地圖)的DOM,並希望更好地映射到API XML信息集。

+0

我正在尋找一個java API來做這件事,而不是使用SAX和DOM解析器。 – PrasanthNath

+0

這沒有一個標準的API。任何執行此操作的代碼都將調用解析器,可能是SAX解析器。使用SAX來驅動一個樹型構建者 - 這本質上就是你所要求的 - 非常簡單;如果您遇到問題,請查看SAX-DOM適配器(可作爲示例程序廣泛使用)並根據您的需要進行修改。 – keshlam

0

雖然已經很晚了。但是我已經爲XStream API編寫了一個自定義MapEntryConverter,它可以處理任何複雜的XML數據,無論它有多深。即使它會支持重複的標籤名稱(將存儲爲ArrayList)。

XStream xStream = new XStream(new DomDriver()); 
xStream.registerConverter(new MapEntryConverter()); 
xStream.alias("xml", java.util.Map.class); 

// from XML, convert back to map 
Map<String, List<Object>> map = (Map<String, List<Object>>) xStream.fromXML(xmlData); 
/*System.out.println("MAP: \n" + map.entrySet().toString());*/ 

String xml = xStream.toXML(map); 
/*System.out.println("XML: \n"+xml);*/ 

MapEntryConverter.java

import java.util.AbstractMap; 
import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 
import java.util.Map.Entry; 

import com.thoughtworks.xstream.converters.Converter; 
import com.thoughtworks.xstream.converters.MarshallingContext; 
import com.thoughtworks.xstream.converters.UnmarshallingContext; 
import com.thoughtworks.xstream.io.HierarchicalStreamReader; 
import com.thoughtworks.xstream.io.HierarchicalStreamWriter; 

public class MapEntryConverter implements Converter{ 
    @SuppressWarnings("rawtypes") 
    public boolean canConvert(Class clazz) { 
     return AbstractMap.class.isAssignableFrom(clazz); 
    } 

    @SuppressWarnings({ "unchecked" }) 
    public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context) { 
     AbstractMap<String, List<?>> map = (AbstractMap<String, List<?>>) value; 
     List<Map<String, ?>> list = (List<Map<String, ?>>) map.get("xml"); 
     for(Map<String, ?> maps: list) { 
      for(Entry<String, ?> entry: maps.entrySet()) { 
       mapToXML(writer, entry); 
      } 
     } 
    } 

    @SuppressWarnings("unchecked") 
    private void mapToXML(HierarchicalStreamWriter writer, Entry<String, ?> entry) { 
     writer.startNode(entry.getKey()); 
     if(entry.getValue() instanceof String) { 
      writer.setValue(entry.getValue().toString()); 
     }else if( entry.getValue() instanceof ArrayList) { 
      List<?> list = (List<?>) entry.getValue(); 
      for(Object object: list) { 
       Map<String, ?> map = (Map<String, ?>) object; 
       for(Entry<String, ?> entryS: map.entrySet()) { 
        mapToXML(writer, entryS); 
       } 
      } 
     } 
     writer.endNode(); 
    } 

    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { 
     Map<String, List<Object>> map = new HashMap<String, List<Object>>(); 
     map = xmlToMap(reader, new HashMap<String, List<Object>>()); 
     return map; 
    } 

    private Map<String, List<Object>> xmlToMap(HierarchicalStreamReader reader, Map<String, List<Object>> map) { 
     List<Object> list = new ArrayList<Object>(); 
     while(reader.hasMoreChildren()) { 
      reader.moveDown(); 
      if(reader.hasMoreChildren()) { 
       list.add(xmlToMap(reader, new HashMap<String, List<Object>>())); 
      }else { 
       Map<String, Object> mapN = new HashMap<String, Object>(); 
       mapN.put(reader.getNodeName(), reader.getValue()); 
       list.add(mapN); 
      } 
      reader.moveUp(); 
     } 
     map.put(reader.getNodeName(), list); 
     return map; 
    } 

} 

請注意,在每個地圖值存儲爲一個列表中,如果有任何孩子。根據我的理解部分非常整齊。我會在空閒時間拋光並簡化編組部分。

輸入數據應該在下面的xml標籤中提供。

<xml> 
    <person> 
     <name>Rama</name> 
     <age>27</age> 
     <gender>male</gender> 
     <address> 
      <doornumber>234</doornumber> 
      <street>Kanon</street> 
      <city>Hyderabad</city> 
     </address> 
     <qualification> 
      <degree>M.Sc</degree> 
      <specialisation>Maths</specialisation> 
     </qualification> 
     <qualification> 
      <degree>B.E.</degree> 
      <specialisation>Electrical</specialisation> 
     </qualification> 
    </person> 
</xml> 

將我的輸出與您的預期輸出進行比較時發生了一些變化。重複鍵值不會合併爲一個數組,而是它們是單獨的列表。