【问题标题】:JAXB Element With Specific Type But Unknown Names具有特定类型但名称未知的 JAXB 元素
【发布时间】:2017-09-27 08:45:13
【问题描述】:

我有一个根 Xml document (name = "Entity"),其中包含一个已知 Xml element (name = "Header") 和另一个未知名称的 Xml 元素,但已知它有一个内部 XmlElement(name="label")

以下是可能的 Xml:

<Entity>
   <Header>this is a header</Header>
   <a>
     <label>this is element A</label>
     <otherElements/>
   </a>
</Entity>

<Entity>
   <Header>this is a different header</Header>
   <b>
     <label>this is some other element of name b</label>
     <others/>
   </b>
</Entity>

这是我的 JAXB 注释类:

@XmlRootElement(name = "Entity")
@XmlAccessorType(XmlAccessType.NONE)
public class Entity {
    @XmlElement(name = "Header")
    private Header header;

    @XmlElements( {
       @XmlElement(name = "a", type=LabelledElement.A.class), 
       @XmlElement(name = "b", type=LabelledElement.B.class)
    } )
    private LabelledElement labelledElement;

    // constructors, getters, setters...
}

@XmlAccessorType(XmlAccessType.NONE)
public abstract class LabelledElement {
     @XmlElement
     private String label;
     @XmlAnyElement
     private List<Element> otherElements;

     public static class A extends LabelledElement {}
     public static class B extends LabelledElement {}
}

效果很好!但后来我注意到它不仅是&lt;a&gt;&lt;b&gt;

可能是&lt;c&gt;&lt;asd&gt; 甚至是&lt;anything&gt;...

所以列出XmlElement(name = "xyz", type = LabelledElement.xyz.class) 显然不是正确的解决方案。

我只关心Entity#getLabelledElement()#getLabel(),不管LabelledElement 的名字是什么。

这甚至可以通过 JAXB 实现吗?

【问题讨论】:

  • unmarshalling 期间,我也遇到了类似的问题。我正在尝试将 unmarshal 未知元素添加到 Map&lt;String,Object&gt; 中,但它没有按预期工作。我在下面提供的链接中发布了完整的问题。如果你有机会可以看看它并提供你的建议:stackoverflow.com/questions/67648941/…

标签: java xml jaxb


【解决方案1】:

使用 EclipseLink JAXB 实现 (MOXy),这应该可以工作:

@XmlRootElement(name = "Entity")
@XmlSeeAlso({LabelledElement.class}) //Might not be necessary
@XmlAccessorType(XmlAccessType.NONE)
public class Entity {
    @XmlElement(name = "Header")
    private Header header;

    @XmlPath("child::*[position() = 2]")
    @XmlJavaTypeAdapter(MapAdapter.class)
    private Map<String,LabelledElement> labelledElementMap;


    public LabelledElement getLabelledElement(){
         return labelledElementMap.values().get(0);
    }
    // constructors, getters, setters...
}

MapAdapter 类:

public class MapAdapter extends XmlAdapter<MapAdapter.AdaptedMap, Map<String, LabelledElement>> {

    public static class AdaptedMap {

        @XmlVariableNode("key")
        List<LabbeledElement> entries = new ArrayList<LabbeledElement>();

    }

    public static class AdaptedEntry {

        @XmlTransient
        public String key;

        @XmlElement
        public LabelledElement value;

    }

    @Override
    public AdaptedMap marshal(Map<String, LabelledElement> map) throws Exception {
        AdaptedMap adaptedMap = new AdaptedMap();
        for(Entry<String, LabelledElement> entry : map.entrySet()) {
            AdaptedEntry adaptedEntry = new AdaptedEntry();
            adaptedEntry.key = entry.getKey();
            adaptedEntry.value = entry.getValue();
            adaptedMap.entries.add(adaptedEntry);
        }
        return adaptedMap;
    }

    @Override
    public Map<String, LabelledElement> unmarshal(AdaptedMap adaptedMap) throws Exception {
        List<AdaptedEntry> adaptedEntries = adaptedMap.entries;
        Map<String, LabelledElement> map = new HashMap<String, LabelledElement>();
        for(AdaptedEntry adaptedEntry : adaptedEntries) {
            map.put(adaptedEntry.key, adaptedEntry.value);
        }
        return map;
    }

}

作为参考,我的解决方案灵感来自this link

【讨论】:

  • 感谢您的回答,但是,这无济于事。即使我不关心“otherElements”,我也将 Xml 编组到文件中,但我需要读取标签值。
  • @user640853 抱歉,它没有帮助,您能否再解释一下您在编组时所期望的结果?
  • 我需要按原样编组 Xml,这意味着保留 labelledElement 下的所有元素和属性,但我需要读取标签 &lt;Entity&gt;&lt;Header&gt;header&lt;/Header&gt;&lt;asd&gt;&lt;label&gt;label asd&lt;/label&gt;&lt;otherElements&gt;&lt;/otherElements&gt;&lt;/asd&gt;&lt;/Entity&gt; 的值使用您的解决方案,我会丢失otherElements元素
  • @user640853 已更改答案,请检查它是否适合您。
  • 切换到 MOXy impl 是不可行的;但是,这回答了我的问题。谢谢
【解决方案2】:

显然,EclipseLink JAXB (MOXy) 实现是可能的,它允许您注释接口变量,提供将 XML 绑定到 Java 时要使用的工厂类和方法,请参阅answer

(经过编辑以提供此方法的示例) 例如,你不是有一个抽象类 LabelledElement,而是有一个接口 LabelledElement

public interface LabelledElement {
    String getLabel();
}

然后让 类 A 和 B 实现它,如下所示:

import javax.xml.bind.annotation.XmlElement;

public class A implements LabelledElement{

    private String label;

    @Override
    @XmlElement(name="label")
    public String getLabel() {
        return label;
    }
}

实体类注释如下:

@XmlRootElement(name = "Entity")
@XmlAccessorType(XmlAccessType.NONE)
public class Entity {
    @XmlElement(name = "Header")
    private Header header;

    @XmlRootElement
    @XmlType(
    factoryClass=Factory.class, 
    factoryMethod="createLabelledElement")
    private LabelledElement labelledElement;

    // constructors, getters, setters...
}

然后,正如我所链接的答案所暗示的,您需要一个 Factory 类,例如:

import java.lang.reflect.*;
import java.util.*;

public class Factory {

    public A createA() {
        return createInstance(A.class);
    }

    public B createB() {
        return createInstance(B.class);;
    }

    private <T> T createInstance(Class<T> anInterface) {
        return (T) Proxy.newProxyInstance(anInterface.getClassLoader(), new Class[] {anInterface}, new InterfaceInvocationHandler());
    }

    private static class InterfaceInvocationHandler implements InvocationHandler {

        private Map<String, Object> values = new HashMap<String, Object>();

        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            String methodName = method.getName();
            if(methodName.startsWith("get")) {
                return values.get(methodName.substring(3));
            } else {
                values.put(methodName.substring(3), args[0]);
                return null;
            }
        }

    }
}

【讨论】:

  • 嗯,不是真的!答案显示了如何使用 JAXB 为相同的元素名称但具有不同类型的注释,这与我正在寻找的答案相反。
  • @user640853 以我编辑的回复为例,说明我如何使用接口、工厂类和 MOXy JAXB 实现对其进行修改。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-29
相关资源
最近更新 更多