JAXB:根据元素值解组子类 [英] JAXB: Unmarshal to subclass based on element value

查看:56
本文介绍了JAXB:根据元素值解组子类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用包含项列表的JAXB解析XML文件.项目的类别取决于XML中元素的值.

I am trying to parse an XML file using JAXB which contains a list of items. The class of the items depends on the value of an element in the XML.

这是一个旧系统,我无法轻松更改输入格式.

This is a legacy system and I can't easily change the input format.

例如,给定以下XML和类定义:

For example, given the following XML and class definitions:

<root>
    <type>a</type>
    <item>
       <a>a1</a>
    </item>
    <item>
       <a>a2</a>
    </item>
</root>

@XmlRootElement(name = "root")
public class Root {
    @XmlElement
    String type;

    @XmlElement(name="item")
    List<Item> items;
}

public class Item {}
public class ItemA extends Item {
    @XmlElement
    String a;
}
public class ItemB extends Item {
    @XmlElement
    String b;
}

从现在开始,项目列表包含两个Item对象.

As it works now, the items list contains two Item objects.

我需要生成的Root对象中的项目列表包含两个ItemA对象,一个对象带有a ="a1",另一个带有a ="a2".

I need the items list in the resulting Root object to contain two ItemA objects, one with a="a1" and the other with a="a2".

如果type元素为"b",则我需要项目列表包含ItemB对象.

If the type element is "b", I need the items list to contain ItemB objects.

在一个XML文件中只能指定一个类型元素.

There will only be one type element specified in a single XML file.

我看到了几种使用属性值的解决方案,但是没有使用元素值的解决方案.

I have seen several solutions using attribute values, but none using element values.

推荐答案

按照

Following the tip of Blaise Doughan you could create an XmlAdapter. Unfortunately Adapters are not available on the root level so you would have to add a bit extra code during un-/marshalling.

Root/Item/ItemA/ItemB是纯POJO,此处没有任何注释.

Root/Item/ItemA/ItemB are plain POJOs without any annotations here.

具有适应类型的适配器:

The Adapter with the adapted types:

public class RootAdapter extends XmlAdapter<AdaptedRoot, Root>
{
    @Override
    public Root unmarshal( AdaptedRoot v ) throws Exception
    {
        Root root = new Root();
        root.type = v.type;
        for ( AdaptedItem adaptedItem : v.items )
        {
            if ( v.type.equals( "a" ) )
            {
                ItemA a = new ItemA();
                a.a = adaptedItem.a;
                root.items.add( a );
            }
            if ( v.type.equals( "b" ) )
            {
                ItemB b = new ItemB();
                b.b = adaptedItem.b;
                root.items.add( b );
            }
        }
        return root;
    }

    @Override
    public AdaptedRoot marshal( Root v ) throws Exception
    {
        AdaptedRoot adapted = new AdaptedRoot();
        adapted.type = v.type;
        for ( Item item : v.items )
        {
            AdaptedItem adaptedItem = new AdaptedItem();
            if ( v.type.equals( "a" ) )
            {
                adaptedItem.a = ((ItemA) item).a;
            }
            if ( v.type.equals( "b" ) )
            {
                adaptedItem.b = ((ItemB) item).b;
            }
            adapted.items.add( adaptedItem );
        }
        return adapted;
    }

    @XmlRootElement( name = "root" )
    public static class AdaptedRoot
    {
        @XmlElement
        String            type;
        @XmlElement( name = "item" )
        List<AdaptedItem> items = new ArrayList<>();
    }

    public static class AdaptedItem
    {
        @XmlElement
        String a;
        @XmlElement
        String b;
    }
}

解组/编组可以这样进行:

Un-/marshalling could be done like this:

public static void main( String[] args ) throws Exception
{
    String rawRootA = "<root><type>a</type><item><a>a1</a></item><item><a>a2</a></item></root>";
    String rawRootB = "<root><type>b</type><item><b>b1</b></item><item><b>b2</b></item></root>";

    Root rootA = unmarshal( rawRootA );
    for ( Item item : rootA.items )
    {
        System.out.println( item.getClass().getSimpleName() );
    }
    print( rootA );

    Root rootB = unmarshal( rawRootB );
    for ( Item item : rootB.items )
    {
        System.out.println( item.getClass().getSimpleName() );
    }
    print( rootB );
}

public static Root unmarshal( String xml ) throws Exception
{
    JAXBContext context = JAXBContext.newInstance( AdaptedRoot.class );
    Unmarshaller unmarshaller = context.createUnmarshaller();
    XmlAdapter<AdaptedRoot, Root> adapter = new RootAdapter();

    AdaptedRoot adapted = (AdaptedRoot) unmarshaller.unmarshal( new StringReader( xml ) );
    return adapter.unmarshal( adapted );
}

public static void print( Root root ) throws Exception
{
    JAXBContext context = JAXBContext.newInstance( AdaptedRoot.class );
    Marshaller marshaller = context.createMarshaller();
    marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, true );
    XmlAdapter<AdaptedRoot, Root> adapter = new RootAdapter();

    AdaptedRoot adaptedRoot = adapter.marshal( root );
    marshaller.marshal( adaptedRoot, System.out );
}

具有预期的输出:

ItemA
ItemA
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
    <type>a</type>
    <item>
        <a>a1</a>
    </item>
    <item>
        <a>a2</a>
    </item>
</root>
ItemB
ItemB
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
    <type>b</type>
    <item>
        <b>b1</b>
    </item>
    <item>
        <b>b2</b>
    </item>
</root>

这篇关于JAXB:根据元素值解组子类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆