2010-01-11 99 views
6

我有一個XML文檔(由Adobe XFA表單生成的),其中包含類似下面的數據:XStream的:摺疊XML的層次結構,我解析

<Position> 
    <PositionBorder> 
     <Title/> 
     <StartDate/> 
     <EndDate/> 
    </PositionBorder> 
</Position> 

由於此文件在其他地方定義,我不隨意更改我得到的XML格式。

在我的Java代碼中,我創建了一個Position類,其中包含標題,開始日期和結束日期。

我的問題是,當我使用XStream來解析文件時,它想要一個PositionBorder類來保存標題和日期。我想基本忽略邊界並將所有字段放置到Position類中。

我真的很想做的就是使用類似convertAnother方法來轉換position元素的子元素。我試圖做到這一點,它失敗了,因爲我的PositionConverter被調用了PositionBorder(當我調用convertAnother時)。

任何人有任何線索如何處理解析時崩潰XML的結構?

+0

做ü必須使用西河解析XML? – 2010-01-11 23:56:41

+0

它不是一個要求,但我有很多現有的代碼投入,所以我現在不想改變。 – Steve 2010-01-12 14:04:24

回答

4

使用自定義轉換器並不難。這是一個長期的例子一點點,但我希望這是很簡單的瞭解你需要做什麼要點:

import com.thoughtworks.xstream.XStream; 
import com.thoughtworks.xstream.annotations.XStreamAlias; 
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 final class ConverterTest { 
    public static void main(String[] args) { 
     XStream xstream = new XStream(); 
     xstream.autodetectAnnotations(true); 
     xstream.registerConverter(new PositionConverter()); 

     final Position position = new Position(); 
     position.setTitle("The Title"); 
     position.setStartDate("The Start Date"); 
     position.setEndDate("The End Date"); 

     final String xml = xstream.toXML(position); 
     System.out.println("Generated XML:"); 
     System.out.println(xml); 

     final Position genPosition = (Position) xstream.fromXML(xml); 
     System.out.println("Generated Position:"); 
     System.out.println("\tTitle: " + genPosition.getTitle()); 
     System.out.println("\tStart Date: " + genPosition.getStartDate()); 
     System.out.println("\tEnd Date: " + genPosition.getEndDate()); 
    } 

    @XStreamAlias("Position") 
    private static class Position { 
     public String getEndDate() { 
      return endDate; 
     } 

     public void setEndDate(String endDate) { 
      this.endDate = endDate; 
     } 

     public String getStartDate() { 
      return startDate; 
     } 

     public void setStartDate(String startDate) { 
      this.startDate = startDate; 
     } 

     public String getTitle() { 
      return title; 
     } 

     public void setTitle(String title) { 
      this.title = title; 
     } 

     private String title; 
     private String startDate; 
     private String endDate; 
    } 

    private static class PositionConverter implements Converter { 
     public boolean canConvert(Class clazz) { 
      return Position.class == clazz; 
     } 

     public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context) { 
      Position position = (Position)value; 
      writer.startNode("PositionBorder"); 

      writer.startNode("Title"); 
      writer.setValue(position.getTitle()); 
      writer.endNode(); 

      writer.startNode("StartDate"); 
      writer.setValue(position.getStartDate()); 
      writer.endNode(); 

      writer.startNode("EndDate"); 
      writer.setValue(position.getEndDate()); 
      writer.endNode(); 

      writer.endNode(); 
     } 

     public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { 
      Position position = new Position(); 
      // move it to <PositionBorder> tag. 
      reader.moveDown(); 
      // now move it to <Title> tag. 
      reader.moveDown(); 
      String title = reader.getValue(); 
      position.setTitle(title); 
      reader.moveUp(); // moves back to <PositionBorder> 

      reader.moveDown(); // should move down to <StartDate> tag 
      String startDate = reader.getValue(); 
      position.setStartDate(startDate); 
      reader.moveUp(); // move back to <PositionBorder> 

      reader.moveDown(); // should move down to <EndDate> tag 
      String endDate = reader.getValue(); 
      position.setEndDate(endDate); 
      reader.moveUp(); // move back to <PositionBorder> 


      return position; 
     } 
    } 
} 

試運行,看看會發生什麼。你需要修改它以適應你自己的類型 - 當然,我只是對所有Position的字段使用了字符串(並且我確定你是Position類不是嵌套的),但是從String到日期(或其他)應該是相當微不足道的。

你需要關注的一件事(我可能沒有得到它完全在我的例子中)是匹配你的reader.moveDown()和reader.moveUp()調用。 (而且,如果你打算做任何編組而不是解組 - 而我從你的問題中不期望 - 你會想要匹配你的writer.startNode()和writer.endNode()調用)這個例子可能不會造成任何問題,但是我相信如果你做了更大的任務或者使用同一個XStream或者Converter實例處理多個文件,它會引發問題。另外,如果你從一個無效位置嘗試reader.moveDown(),你會得到一個非常難看的異常 - 它應該是非常明顯的。

爲了讓它們位於正確的位置,我不得不使用moveUp/moveDown方法,所以我相信你需要測試它並調整它,直到你得到你所需要的。

+1

你解組的代碼'String title = reader.getValue();'如果節點的順序不相同,可能會報錯。 'String title = reader.getAttribute(「attributeName」);'應該使它更安全。 – n002213f 2010-07-15 13:31:11

0

我覺得這種方式更容易使用:

@Override 
    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { 
     Position mPosition = new Position(); 
     while (reader.hasMoreChildren()) { 

      reader.moveDown(); 

      String nodeName = reader.getNodeName(); 

      if ("Title".equalsIgnoreCase(nodeName)) { 
       mPosition.setTitle(reader.getValue()); 
      } else if ("StartDate".equalsIgnoreCase(nodeName)) { 
       mPosition.setStartDate(reader.getValue()); 
      }else if ("attributeexample".equalsIgnoreCase(nodeName)) { 
       mPosition.setAttributeExample(reader.getAttribute("attrname")); 
      } 

      reader.moveUp(); 
     } 

     return mPosition; 
    }