我有一个XML文档(由Adobe XFA表单生成),其中包含如下数据:
<Position>
<PositionBorder>
<Title/>
<StartDate/>
<EndDate/>
</PositionBorder>
</Position>
由于此文件是在其他地方定义的,因此我无权更改我获得的XML格式。
在我的Java代码中,我创建了一个包含Title,Start和End Dates的Position类。
我的问题是,当我使用XStream解析文件时,它需要一个PositionBorder类来保存标题和日期。我想基本上忽略边框并将所有字段放入Position类。
我真正想做的是使用convertAnother方法转换position元素的子元素。我试图这样做但它失败了,因为我的PositionConverter被调用了PositionBorder(当我调用convertAnother时)。
任何人都有任何线索如何处理在解析时折叠XML的结构?
答案 0 :(得分: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 :(得分: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;
}