当前位置: 首页 > 面试题库 >

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

余信然
2023-03-14
问题内容

我有一个包含许多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元素反序列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;
}

问题答案:

现在真正的问题…

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


 类似资料:
  • 问题内容: 使用Jackson 2,我正在寻找一种 通用的 方式将对象序列化为单个值(然后序列化它们,然后再填充该单个字段),而不必重复创建JsonSerializer / JsonDeserializer来处理每种情况。@JsonIdentityInfo批注非常接近,但由于我知道,它将始终对完整的子对象进行序列化,因此略微遗漏了该标记。 这是我想做的一个例子。给定的类: 我希望Order可以序列

  • 问题内容: 可以说我有以下格式的JSON: 我试图避免自定义反序列化器,并尝试将上述JSON(称为Wrapper.java)反序列化为Java POJO。“类型”字段指示“对象”反序列化,即。type = foo表示使用Foo.java反序列化“ object”字段。(如果type = Bar,则使用Bar.java反序列化对象字段)。元数据/所有者将始终使用相同的反序列化方式,每个方法都使用一个

  • 假设我有以下格式的JSON: 我试图避免自定义反序列化程序,并试图将上述JSON(称为Wrapper.java)反序列化为JavaPOJO。“type”字段指示“object”反序列化,即type=foo表示使用foo.java反序列化“object”字段。(如果type=Bar,则使用Bar.java反序列化对象字段)。Metadata/owner将始终以相同的方式对每个元数据使用简单的带Jac

  • 我有一个REST API,它返回JSON响应为: 有时它会返回: 我有一个这样的POJO: 那么,有没有办法(除了编写自己的自定义反序列化程序)在 Jackson2 中帮助我将 JSON 中的通道映射到字符串类型(当它是时)和类型(当它是 JSON 对象时)? 或者换句话说,Jackson中是否有一种方法可以通过变量的映射,而不仅仅是通过?

  • 问题内容: 我正在针对返回JSON数据的第三方API进行编程,但是格式可能有点奇怪。某些属性可以是一个对象(包含一个Id属性),也可以是一个字符串(它是该对象的ID)。例如,以下两个都是有效的: 和 我正在尝试使用JSON.net将其反序列化为强类型类,但到目前为止运气还不足。我最好的主意是将其序列化为两个属性,一个为字符串,另一个为对象,并为每个属性使用自定义JsonConverter以允许变量

  • 有人能帮我把它弄好吗。谢谢你。