反序列化的XML元素,以不同的类型,基于属性(Deserialize XML elements to

2019-10-20 23:04发布

我有许多的XML文档Entity元件,其各自具有的属性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>

我需要一种方法来告诉简单的反序列化Entity的元素type="foo"到一个List<FooEntity>并与元素type="bar"到一个List<BarEntity>

我怎样才能做到这一点?

这里是如果你要玩它我目前拥有的代码:

public class App {
    public static void main(String[] args) throws Exception {
        Reader r = Files.newBufferedReader(
            Paths.get("/path/to/file.xml"),
            Charset.defaultCharset()
        );
        Serializer serializer = new Persister();

        RootNode root = serializer.read(RootNode.class, r);
        System.out.println(root.getFooEntities().size());
        System.out.println(root.getBarEntities().size());
    }
}

@Root(name = "RootNode")
class RootNode {

    // TODO: What annotations to put here?
    private List<FooEntity> fooEntities;

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

    public List<FooEntity> getFooEntities() { return fooEntities; }
    public List<BarEntity> getBarEntities() { return barEntities; }
}

class FooEntity {
    @Element(name = "URL")
    private String url;
}

class BarEntity {
    @Element(name = "Price")
    private int price;
}

Answer 1:

现在真正的问题...

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

我的回答:没有! 或者至少,没关系!

像属性type ,这里只是字符串,而不能作出任何决定。 但还有另一种不错的方式:

  1. 实现了转换RootNode这确实决定
  2. 使用Serializer做反序列化每个实体的实际工作。

我做了一些修改你的类,但没有壮观已经改变。 的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))或ErrorHandling中一般。

顺便说一句。 而不是两个列表,您可以维护一个单一的一个(如果相关)。 只是要为实体的超类。 您可以在移动type -attribute到那里了。

用法

下面是一个例子如何使用:

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}]}


文章来源: Deserialize XML elements to different types, based on attribute