簡體   English   中英

用Jaxb解組嵌套地圖

[英]Unmarshal nested Map with Jaxb

我需要以下DTO

@XmlRootElement(name = "exchangerate")
@XmlAccessorType(XmlAccessType.FIELD)
public class ExchRates {

    @XmlJavaTypeAdapter(DateAdapter.class)
    private Date date;

    @XmlJavaTypeAdapter(JaxbExchangeRatesMapAdapter.class)
    private Map<CurrencyUnit, Map<CurrencyUnit, Double>> rates = new HashMap<>();
}

我如何將該XML解組到上面的DTO中?

<exchangerate>
    <date>2015-05-04</date>
    <EUR>
        <EUR>1</EUR>
        <GBP>0.73788</GBP>
        <USD>1.1152</USD>
    </EUR>
    <GBP>
        <EUR>1.35523</EUR>
        <GBP>1</GBP>
        <USD>1.51136</USD>
    </GBP>
    <USD>
        <EUR>0.8967</EUR>
        <GBP>0.66166</GBP>
        <USD>1</USD>
    </USD>
</exchangerate>

我讀了一些教程和示例,但沒有發現所有鍵都是xml的節點值的人。

編輯

幾個小時后,我就要解決了。

我的XmlAdapter:

public class JaxbExchangeRatesMapAdapter extends XmlAdapter<JaxbExchangeRatesMap, Map<CurrencyUnit, Map<CurrencyUnit, Double>>> {

    @Override
    public Map<CurrencyUnit, Map<CurrencyUnit, Double>> unmarshal(JaxbExchangeRatesMap v) throws Exception {
        return null;
    }

    @Override
    public JaxbExchangeRatesMap marshal(Map<CurrencyUnit, Map<CurrencyUnit, Double>> v) throws Exception {
        JaxbExchangeRatesMap map = new JaxbExchangeRatesMap();

        for (CurrencyUnit currencyFrom : v.keySet()) {
            Map<CurrencyUnit, Double> from = v.get(currencyFrom);
            JaxbExchangeRatesEntry entry = new JaxbExchangeRatesEntry();
            for (CurrencyUnit currencyTo : from.keySet()) {
                entry.getEntries().add(new JAXBElement<>(new QName(currencyTo.getCurrencyCode()), Double.class, from.get(currencyTo)));
            }
            JAXBElement<JaxbExchangeRatesEntry> jaxbElement = new JAXBElement<>(new QName(currencyFrom.getCurrencyCode()), JaxbExchangeRatesEntry.class, entry);
            map.getEntires().add(jaxbElement);
        }
        return map;
    }

}

和我的映射類:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlSeeAlso(JaxbExchangeRatesEntry.class)
public class JaxbExchangeRatesMap extends Printable {

    private static final long serialVersionUID = 15543456767150881L;

    @XmlAnyElement
    private List<JAXBElement<JaxbExchangeRatesEntry>> entires = new ArrayList<>();

    public List<JAXBElement<JaxbExchangeRatesEntry>> getEntires() {
        return entires;
    }

    public JaxbExchangeRatesMap setEntires(List<JAXBElement<JaxbExchangeRatesEntry>> entires) {
        this.entires = entires;
        return this;
    }
}

@XmlAccessorType(XmlAccessType.FIELD)
public class JaxbExchangeRatesEntry extends Printable {

    private static final long serialVersionUID = -694282168028218725L;

    @XmlAnyElement
    private List<JAXBElement<Double>> entries = new ArrayList<>();

    public List<JAXBElement<Double>> getEntries() {
        return entries;
    }

    public JaxbExchangeRatesEntry setEntries(List<JAXBElement<Double>> entries) {
        this.entries = entries;
        return this;
    }
}

這樣我得到了以下結果:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<exchangerate>
    <rates>
        <USD>
            <USD>9.0</USD>
            <EUR>7.0</EUR>
            <GBP>8.0</GBP>
        </USD>
        <EUR>
            <USD>3.0</USD>
            <EUR>1.0</EUR>
            <GBP>2.0</GBP>
        </EUR>
        <GBP>
            <USD>6.0</USD>
            <EUR>4.0</EUR>
            <GBP>5.0</GBP>
        </GBP>
    </rates>
</exchangerate>

如何刪除/跳過費率標簽?

我建議您將XML結構如下:

<exchangerate>
    <date>2015-05-04</date>
    <currency code="EUR">
        <rate code="EUR">1</rate >
        <rate code="GBP">0.73788</rate >
        <rate code="USD">1.1152</rate >
    </currency>
    <currency code="GBP">
        <rate code="EUR">1.35523</rate >
        <rate code="GBP">1</rate >
        <rate code="USD">1.51136</rate >
    </currency>
    <currency code="USD">
        <rate code="EUR">0.8967</rate >
        <rate code="GBP">0.66166</rate >
        <rate code="USD">1</rate >
    </currency>
</exchangerate> 

並且您有多個課程:

@XmlAccessorType(XmlAccessType.FIELD)
public class ExchangeRates {
    @XmlJavaTypeAdapter(DateAdapter.class)
    private Date date;

    @XmlElement(name="currency")
    private List<Currency> currencies = new ArrayList<>();

    ....
}

@XmlAccessorType(XmlAccessType.FIELD)
public class Currency {
    @XmlAttribute
    private String code;

    @XmlElement(name="rate")
    private List<Rate> rates= new ArrayList<>();

    ....
}


@XmlAccessorType(XmlAccessType.FIELD)
public class Rate {
    @XmlAttribute
    private String code;

    @XmlValue
    private Double value;

    ....
}

如果您要堅持問題開頭所描述的原始XML結構,那么使用@XmlJavaTypeAdapter很難或不可能解決。 但是您可以重復使用從答案到“要映射的JAXB節點”的替代方法,並將其應用於您的情況:

在您的ExchRates類中,聲明一個用@XmlAnyElement注釋的List<Element> ,以便JAXB將其用於編組/解組。

但您需要Map<CurrencyUnit, Map<CurrencyUnit, Double>>Map<String, Map<String, Double>> (我不知道如何創建CurrencyUnit ,因此我的解決方案使用String 。)因此,您也聲明了這一點,但使用@XmlTransient注釋,因此JAXB不會將其用於編組/解組。

最后,在afterUnmarshal(Unmarshaller unmarshaller, Object parent)實現一個私有方法,在該方法中,您將內容從List<Element>鏟到Map<String, Map<String, Double>> Unmarshal事件回調中所述,JAXB將在適當的時間調用此方法。

如果需要編寫XML文件,則可能還需要在beforeMmarshal(Marshaller marshaller)使用私有方法,在該方法中,將內容從Map<String, Map<String, Double>>返回到List<Element> 元帥事件回調中所述,JAXB將在適當的時間調用此方法。

@XmlRootElement(name = "exchangerate")
@XmlAccessorType(XmlAccessType.FIELD)
public class ExchRates {

    private Date date;

    @XmlAnyElement
    private List<Element> elements;

    @XmlTransient  // don't participate in JAXB marshalling/unmarshalling
    private Map<String, Map<String, Double>> rates;

    @SuppressWarnings("unused")  // called only by JAXB
    private void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {
        rates = new HashMap<>();
        for (Element element : elements) {
            String currencyUnit = element.getTagName();
            NodeList subElements = element.getElementsByTagName("*");
            Map<String, Double> subMap = new HashMap<>();
            for (int i = 0; i < subElements.getLength(); i++) {
                Element subElement = (Element) subElements.item(i);
                String currencyUnit2 = subElement.getTagName();
                double value = Double.parseDouble(subElement.getTextContent());
                subMap.put(currencyUnit2, value);
            }
            rates.put(currencyUnit, subMap);
        }   
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM