小编典典

根据属性将XML元素反序列化为不同类型

java

我有一个包含许多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>

我需要一种方法告诉SimpleEntity元素反序列type="foo"化为a
List<FooEntity>和将元素反序列type="bar"化为a 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;
}

阅读 244

收藏
2020-11-30

共1个答案

小编典典

现在真正的问题…

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

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

type这里这样的属性只是字符串,不能做出任何决定。但是还有另一种好方法:

  1. 实施要RootNode为其做出决定的转换器
  2. 使用a 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))通常添加或错误处理。

顺便说一句。而不是 2个 列表,您可以维护一个 单一的 一个(如果相关)。只需为实体创建超类。您也可以将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}]}
2020-11-30