6

我有一个 XML 文档(由 Adob​​e XFA 表单生成),其中包含如下数据:

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

由于这个文件是在别处定义的,我不能随意更改我得到的 XML 的格式。

在我的 Java 代码中,我创建了一个包含 Title、Start 和 End Dates 的 Position 类。

我的问题是,当我使用 XStream 解析文件时,它需要一个 PositionBorder 类来保存标题和日期。我想基本上忽略边框并将所有字段放入 Position 类。

我真正想做的是使用类似 convertAnother 方法来转换位置元素的子元素。我试图这样做但它失败了,因为我的 PositionConverter 被调用为 PositionBorder(当我调用 convertAnother 时)。

任何人都知道如何在解析时处理折叠 XML 的结构?

4

2 回答 2

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 方法来将它们放在正确的位置,所以我相信你需要对其进行测试和调整,直到你得到你需要的东西。

于 2010-02-23T23:55:37.107 回答
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;
    }
于 2010-11-12T19:55:34.150 回答