简体   繁体   English

使用JAXB将具有类似地图结构的xml解组为对象

[英]Using JAXB to unmarshal xml with map-like structure to object

I'm trying to unmarshal poorly designed XML into an object. 我正在尝试将设计不良的XML解组为对象。 The XML was built using a generic type element which can have any number of items with any name . XML是使用泛型type元素构建的,该元素可以包含任意数量的具有任何nameitems Depending on the value of type in Something below, the include properties will be different. 根据下面Something中的type值,include属性将有所不同。 It's basically just bypassing the XSD rulse (yes, it has a XSD, but it's utterly useless). 它基本上只是绕过了XSD的冲动(是的,它有一个XSD,但它完全没用)。

The XML I get: 我得到的XML:

<Something type="actualType">
   <Property name="prop1">value1</Property>
   <Property name="prop2">value2</Property>
   ...
</Something>

What it should have been: 应该是什么:

<actualType>
   <prop1>Value1</prop1>
   <prop2>Value2</prop1>
</actualType>

How it should be represented in Java: 它应该如何用Java表示:

@XmlType(name="actualType")
public class ActualType
{
   @XmlElement
   public X prop1

   @XmlElement
   public Y prop2

}

The actual question(s): 实际问题:

Is there any basic support for something like this in Jaxb (without external dependencies)? 在Jaxb中是否有类似这样的基本支持(没有外部依赖)? If not, can I write custom annotations such that I will be able to reuse the same logic for other services using this schema? 如果没有,我可以编写自定义注释,以便我可以使用此模式为其他服务重用相同的逻辑吗?

There are a couple of ways you could support this use case: 您可以通过以下几种方式支持此用例:

OPTION #1 - Any JAXB (JSR-222) Implementation 选项#1 - 任何JAXB(JSR-222)实现

If you only need to read the XML to objects, then you could leverage a StreamReaderDelegate and do the following. 如果您只需要将XML读取到对象,那么您可以利用StreamReaderDelegate并执行以下操作。 Basically it makes the bad XML appear as if it were the good XML: 基本上它会使坏的XML看起来好像是好的XML:

import javax.xml.bind.*;
import javax.xml.stream.*;
import javax.xml.stream.util.StreamReaderDelegate;
import javax.xml.transform.stream.StreamSource;

public class Demo {

    public static void main(String[] args) throws Exception {

        XMLInputFactory xif = XMLInputFactory.newFactory();
        XMLStreamReader xsr = xif.createXMLStreamReader(new StreamSource("src/forum16529016/input.xml"));

        xsr = new StreamReaderDelegate(xsr) {

            @Override
            public String getLocalName() {
                String localName = super.getLocalName();
                if(!"Property".equals(localName) && super.getEventType() == XMLStreamReader.START_ELEMENT) {
                    return localName;
                }
                if(super.getEventType() == XMLStreamReader.START_ELEMENT) {
                    return super.getAttributeValue(null, "name");
                }
                return localName;
            }
        };

        JAXBContext jc = JAXBContext.newInstance(ActualType.class);
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        ActualType actualType = unmarshaller.unmarshal(xsr, ActualType.class).getValue();
        System.out.println(actualType.prop1);
        System.out.println(actualType.prop2);
    }
}

OPTION #2 - EclipseLink JAXB (MOXy's) @XmlPath Extension 选项#2 - EclipseLink JAXB(MOXy的)@XmlPath扩展

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group. 注意:我是EclipseLink JAXB(MOXy)的负责人,也是JAXB(JSR-222)专家组的成员。

MOXy has an @XmlPath extension that enables you to map this use case. MOXy有一个@XmlPath扩展,使您可以映射此用例。

import javax.xml.bind.annotation.XmlType;
import org.eclipse.persistence.oxm.annotations.XmlPath;

@XmlType(name="actualType")
public class ActualType
{
   @XmlPath("Property[@name='prop1']/text())
   public X prop1

   @XmlPath("Property[@name='prop1']/text())
   public Y prop2

}

For More Information 欲获得更多信息

This is not a direct answer to your question, but you could simply read the bad xml's as they are in object Bad and then define the class Good with constructor Good(Bad bad). 这不是你的问题的直接答案,但你可以简单地读取坏对象,因为它们在对象Bad中,然后用构造函数Good(Bad bad)定义类Good。 The Good class would have the properties defined as members and its constructor would fetch them from the Bad object. Good类将属性定义为成员,其构造函数将从Bad对象中获取它们。

An alternative would be to have just one class, but keeping the "bad" members private and then calling some method after the unmarshalling to fill up the good members (which are untouched by jaxb). 另一种方法是只有一个类,但保持“坏”成员私有,然后在解组后调用一些方法来填充好成员(jaxb不受影响)。 See callback . 请参阅回调

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM