代码之家  ›  专栏  ›  技术社区  ›  Steve

XStream:在分析时折叠XML层次结构

  •  6
  • Steve  · 技术社区  · 16 年前

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

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

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

    在Java代码中,我创建一个包含标题、开始日期和结束日期的位置类。

    我的问题是,当我使用xstream解析文件时,它需要一个positionborder类来保存标题和日期。我想基本上忽略边界,并将所有字段放到position类中。

    我真正想做的是使用convertanother方法来转换position元素的子元素。我试图这样做,但失败了,因为我的positionconverter被调用为positionborder(当我调用convertanother时)。

    有人知道在解析时如何处理XML结构的崩溃吗?

    2 回复  |  直到 15 年前
        1
  •  4
  •   MCory    16 年前

    使用自定义转换器并不难。这是一个有点长的例子,但我希望它足够简单,以获得您需要做的事情的要点:

    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类也没有嵌套),但是从字符串转换为日期(或其他)应该是非常简单的。

    有件事你要注意(我可能还没弄到) 完全地 在我的示例中)正在匹配您的reader.movedown()和reader.moveup()调用。(而且,如果您要执行任何编组而不仅仅是解组(我不希望从您的问题中看到这一点),您还需要匹配writer.startnode()和writer.endnode()调用。)它可能不会对本例造成任何问题,但我相信如果您执行更大的操作或处理多个fil,它会引发问题。具有相同xstream或converter实例的。另外,如果您从一个无效的位置尝试reader.movedown(),您将得到一个非常糟糕的异常——这应该是非常明显的。

    我必须在moveup/movedown方法中进行一些调整,以使它们处于正确的位置,所以我确信您需要测试和调整它,直到您得到所需的。

        2
  •  0
  •   kospol    15 年前

    我发现这样更容易使用:

    @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;
        }