XStream:在我解析时折叠XML层次结构
我有一个XML文档(由Adobe XFA表单生成),其中包含如下数据:
由于此文件是在其他地方定义的,因此我无权更改我获得的XML格式。
在我的Java代码中,我创建了一个包含Title,Start和End Dates的Position类。
我的问题是,当我使用XStream来解析文件时,它需要一个PositionBorder类来保存标题和日期。 我想基本上忽略边框并将所有字段放入Position类。
我真正想做的是使用像convertAnother方法这样的东西来转换position元素的子元素。 我试图这样做但它失败了,因为我的PositionConverter被调用了PositionBorder(当我调用convertAnother时)。
任何人都有任何线索在解析时如何处理折叠XML的结构?
使用自定义转换器并不是非常困难。 这是一个很长的例子,但我希望它很简单,能够得到你需要做的事情的要点:
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 tag. reader.moveDown(); // now move it to tag. reader.moveDown(); String title = reader.getValue(); position.setTitle(title); reader.moveUp(); // moves back to reader.moveDown(); // should move down to tag String startDate = reader.getValue(); position.setStartDate(startDate); reader.moveUp(); // move back to reader.moveDown(); // should move down to tag String endDate = reader.getValue(); position.setEndDate(endDate); reader.moveUp(); // move back to return position; } } }
尝试运行它,看看会发生什么。 你需要修改它以适合你自己的类型 – 当然 – 我只是为所有Position的字段使用了字符串(我确定你的Position类也没有嵌套),但是从String转换到一个日期(或其他)应该是相当微不足道的。
你要注意的一件事(我可能没有在我的例子中完全正确)是匹配你的reader.moveDown()和reader.moveUp()调用。 (并且,如果你打算进行任何编组而不仅仅是解组 – 我不希望你的问题 – 你也想要匹配你的writer.startNode()和writer.endNode()调用。)这个例子可能不会引起任何问题,但我确信如果你做的更大或使用相同的XStream或Converter实例处理多个文件会引发问题。 此外,如果你从一个无效的位置尝试reader.moveDown(),你会得到一个非常丑陋的例外 – 它应该是非常明显的。
我不得不使用moveUp / moveDown方法来使它们在正确的位置,所以我相信你需要测试它并调整它直到你得到你需要的东西。
我发现这种方式更容易使用:
@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; }