基于属性将XML元素反序列化为不同类型

时间:2014-09-15 18:45:59

标签: java android xml simple-framework

我有一个包含许多Entity个元素的XML文档,每个元素的属性都是type="foo"type="bar"。请参阅此示例:

<RootNode>
    <Entities>
        <Entity type="foo">
            <Price>1</Price>
        </Entity>

        <Entity type="bar">
            <URL>www.google.co.uk</URL>
        </Entity>

        <Entity type="foo">
            <Price>77</Price>
        </Entity>
    </Entities>
</RootNode>

我需要一种方法告诉Simple将带有Entity的{​​{1}}元素反序列化为type="foo",将带有List<FooEntity>的元素反序列化为{{1} }}

我该怎么做?

如果您想要使用它,我现在拥有的代码如下:

type="bar"

1 个答案:

答案 0 :(得分:1)

现在真正的问题......

// TODO: What annotations to put here?
private List<BarEntity> barEntities;

我的回答:无!或者至少,它并不重要!

type这样的属性只是字符串而无法做出任何决定。但还有另一个好方法:

  1. 为执行决定的RootNode实施转换器
  2. 使用Serializer执行反序列化每个实体的实际工作。
  3. 我对你的课程进行了一些修改,但没有任何改变。 toString() - 方法仅用于测试 - 根据需要实施。

    班级FooEntity

    @Root(name = "Entity")
    public class FooEntity
    {
        @Attribute(name = "type")
        private String type;
        @Element(name = "Price")
        private int price;
    
        /*
         * NOTE: A default ctor is required - visibile doesn't matter
         */
    
        @Override
        public String toString()
        {
            return "FooEntity{" + "price=" + price + '}';
        }
    }
    

    班级BarEntity

    @Root(name = "Entity")
    public class BarEntity
    {
        @Attribute(name = "type")
        private String type;
        @Element(name = "URL")
        private String url;
    
        /*
         * NOTE: A default ctor is required - visibile doesn't matter
         */
    
        @Override
        public String toString()
        {
            return "BarEntity{" + "url=" + url + '}';
        } 
    }
    

    班级RootNode

    @Root(name = "RootNode")
    @Convert(RootNodeConverter.class)   // <--- Important!
    class RootNode
    {
        private List<FooEntity> fooEntities;
        private List<BarEntity> barEntities;
    
    
        public RootNode()
        {
            // This has to be done somewhere ...
            this.fooEntities = new ArrayList<>();
            this.barEntities = new ArrayList<>();
        }
    
    
        public List<FooEntity> getFooEntities()
        {
            return fooEntities;
        }
    
        public List<BarEntity> getBarEntities()
        {
            return barEntities;
        }
    
        @Override
        public String toString()
        {
            return "RootNode{" + "fooEntities=" + fooEntities + ", barEntities=" + barEntities + '}';
        }
    }
    

    最后是Converter - 实施:

    班级RootNodeConverter

    public class RootNodeConverter implements Converter<RootNode>
    {
        @Override
        public RootNode read(InputNode node) throws Exception
        {
            RootNode root = new RootNode();
            final InputNode entities = node.getNext("Entities");
            InputNode child;
    
            while( ( child = entities.getNext() ) != null )
            {
                if( child.getName().equals("Entity") == false )
                {
                    continue; //  Not an Entity
                }
    
                final Serializer ser = new Persister();
    
                switch(child.getAttribute("type").getValue())
                {
                    case "foo":
                        root.getFooEntities().add(ser.read(FooEntity.class, child));
                        break;
                    case "bar":
                        root.getBarEntities().add(ser.read(BarEntity.class, child));
                        break;
                    default:
                        // Not a Foo nor a Bar - what now!?
                        break;
                }
            }
    
            return root;
        }
    
    
        @Override
        public void write(OutputNode node, RootNode value) throws Exception
        {
            throw new UnsupportedOperationException("Not implemented yet!");
        }
    }
    

    有一些事情需要优化,例如。通常会添加root.addBar(ser.read(BarEntity.class, child))或错误处理。

    顺便说一下。而不是两个列表,您可以维护单个一个(如果相关)。只需为实体创建一个超类。您也可以将type - 属性移动到那里。

    用法

    以下是如何使用的示例:

    final String input = "<RootNode>\n"
            + "    <Entities>\n"
            + "        <Entity type=\"foo\">\n"
            + "            <Price>1</Price>\n"
            + "        </Entity>\n"
            + "\n"
            + "        <Entity type=\"bar\">\n"
            + "            <URL>www.google.co.uk</URL>\n"
            + "        </Entity>\n"
            + "\n"
            + "        <Entity type=\"foo\">\n"
            + "            <Price>77</Price>\n"
            + "        </Entity>\n"
            + "    </Entities>\n"
            + "</RootNode>";
    
    
    final Serializer ser = new Persister(new AnnotationStrategy()); // <-- Note the strategy!
    
    RootNode root = ser.read(RootNode.class, input);
    System.out.println(root);
    

    这里也没什么特别壮观的......

    <强>输出:

    RootNode{fooEntities=[FooEntity{price=1}, FooEntity{price=77}], barEntities=[BarEntity{url=www.google.co.uk}]}