【问题标题】:JAXB unmarshal undefined elements to Map?JAXB 将未定义的元素解组为 Map?
【发布时间】:2019-10-23 07:14:31
【问题描述】:

我有一个要解组的 XML:

<?xml version="1.0" encoding="UTF-8"?>
<ROW id='1'>
   <MOBILE>9831138683</MOBILE>
   <A>1</A>
   <B>2</B>
</ROW>

我想把它映射到一个

import java.util.*;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.eclipse.persistence.oxm.annotations.XmlPath;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class ROW {

    @XmlPath(".")
    @XmlJavaTypeAdapter(MapAdapter.class)
    private Map<String, Integer> map = new HashMap<String, Integer>();

    @XmlAttribute
    private int id;
    @XmlElement(name = "MOBILE")
    private int mobileNo;

}

为此,我尝试了使用 @XmlVariableNode("key")bdoughan 博客:

地图适配器:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlValue;
import javax.xml.bind.annotation.adapters.XmlAdapter;

import org.eclipse.persistence.oxm.annotations.XmlVariableNode;

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

    public static class AdaptedMap {

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

    }

    public static class AdaptedEntry {

        @XmlTransient
        public String key;

        @XmlValue
        public String value;

    }

    @Override
    public AdaptedMap marshal(Map<String, String> map) throws Exception {
        AdaptedMap adaptedMap = new AdaptedMap();
        for(Entry<String, String> 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, String> unmarshal(AdaptedMap adaptedMap) throws Exception {
        List<AdaptedEntry> adaptedEntries = adaptedMap.entries;
        Map<String, String> map = new HashMap<String, String>(adaptedEntries.size());
        for(AdaptedEntry adaptedEntry : adaptedEntries) {
            map.put(adaptedEntry.key, adaptedEntry.value);
        }
        return map;
    }

}

使用这种方法,所有键 (MOBILE, id, A, B) 都映射到 Map 中。我想解组所有已定义的属性 idMOBILE 映射到它们在 POJO 中的属性,其余的都映射到 Map

如何做到这一点?

【问题讨论】:

    标签: java xml jaxb marshalling unmarshalling


    【解决方案1】:

    我有一个解决方案给你,但与你上面尝试的略有不同。

    让我们取根类:

    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlRootElement(name = "ROW")
    public class Row {
    
        @XmlAttribute
        private int id;
        @XmlElement(name = "MOBILE")
        private int mobileNo;
    
        @XmlMixed
        @XmlAnyElement
        @XmlJavaTypeAdapter(MyMapAdapter.class)
        private Map<String, String> otherElements;
    }
    

    以及将 uknown 值转换为地图的适配器:

    import org.w3c.dom.Document;
    import org.w3c.dom.Element;
    
    import javax.xml.bind.annotation.adapters.XmlAdapter;
    import javax.xml.parsers.DocumentBuilderFactory;
    import java.util.HashMap;
    import java.util.Map;
    
    public class MyMapAdapter extends XmlAdapter<Element, Map<String, String>> {
    
        private Map<String, String> hashMap = new HashMap<>();
    
        @Override
        public Element marshal(Map<String, String> map) throws Exception {
            // expensive, but keeps the example simpler
            Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
    
            Element root = document.createElement("dynamic-elements");
    
            for(Map.Entry<String, String> entry : map.entrySet()) {
                Element element = document.createElement(entry.getKey());
                element.setTextContent(entry.getValue());
                root.appendChild(element);
    
            }
    
            return root;
        }
    
    
        @Override
        public Map<String, String> unmarshal(Element element) {
            String tagName = element.getTagName();
            String elementValue = element.getChildNodes().item(0).getNodeValue();
            hashMap.put(tagName, elementValue);
    
            return hashMap;
        }
    }
    

    这会将 id 和手机号码放入字段中,其余的将 uknown 放入地图中。

    编组将与您显示的 xml 不完全相同。它对动态值进行了包装,如下所示:

    <ROW id="1">
        <MOBILE>1241204091</MOBILE>
        <dynamic-elements>
            <A>1</A>
            <B>2</B>
        </dynamic-elements>
    </ROW>
    

    【讨论】:

    • 我在问题中尝试了上面的 XML 字符串示例,解组按预期工作;我有几个问题:A)我应该担心 element.getChildNodes().item(0).getNodeValue() 在 unmarshall 方法中,我看到潜在的 NPE 问题吗? B)如何使马歇尔方法起作用?如果您更新 marshall 方法会很有帮助(我是新手)。
    • @SiddharthTrikha 对于 A,您可以进行所需的检查,以免出现问题。对于 B,这比我预期的要棘手。试图弄清楚。如果/当我管理时,我会更新答案
    • 好的。我猜对于 marshall 方法,我们需要 ListElement
    • @SiddharthTrikha 我还没有想到合适的方法来做到这一点,但在我的尝试中,我将适配器更改为更灵活的方法。我使用对象而不是元素。我会更新答案,希望对你有帮助,今天晚些时候再试一次。
    • @BATMAN_2008 不用担心。会看看,如果我弄清楚了,我会回答这个问题
    猜你喜欢
    • 1970-01-01
    • 2017-02-08
    • 1970-01-01
    • 1970-01-01
    • 2019-05-15
    • 2011-07-16
    • 1970-01-01
    • 1970-01-01
    • 2018-08-27
    相关资源
    最近更新 更多