2010-01-11 98 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; 
    }