Java 用Jaxb解组嵌套映射
我需要下面的DTOJava 用Jaxb解组嵌套映射,java,xml,jaxb,Java,Xml,Jaxb,我需要下面的DTO @XmlRootElement(name = "exchangerate") @XmlAccessorType(XmlAccessType.FIELD) public class ExchRates { @XmlJavaTypeAdapter(DateAdapter.class) private Date date; @XmlJavaTypeAdapter(JaxbExchangeRatesMapAdapter.class) private
@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<>();
}
@XmlRootElement(name=“exchangerate”)
@XmlAccessorType(XmlAccessType.FIELD)
公共级驱逐出境{
@XmlJavaTypeAdapter(DateAdapter.class)
私人日期;
@XmlJavaTypeAdapter(jaxBexChangesMapAdapter.class)
私有映射速率=新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>
2015-05-04
1.
0.73788
1.1152
1.35523
1.
1.51136
0.8967
0.66166
1.
我阅读了一些教程和示例,但没有发现其中所有键都是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;
}
}
公共类JaxbExchangeRatesMapAdapter扩展了XmlAdapter{
@凌驾
公共映射解组器(JAXBEExchangeRatesMap v)引发异常{
返回null;
}
@凌驾
公共JAXBEExchangeRatesMap封送处理(Map v)引发异常{
JaxbExchangeRatesMap map=新的JaxbExchangeRatesMap();
for(CurrencyUnit currencyFrom:v.keySet()){
Map from=v.get(currencyFrom);
JaxbExchangeRatesEntry条目=新的JaxbExchangeRatesEntry();
for(CurrencyUnit currencyTo:from.keySet()){
entry.getEntries().add(新的JAXBElement(新的QName(currencyTo.getCurrencyCode())、Double.class、from.get(currencyTo));
}
JAXBElement-JAXBElement=new-JAXBElement(新的QName(currencyFrom.getCurrencyCode()),JaxbExchangeRatesEntry.class,entry);
map.getEntires().add(jaxbElement);
}
返回图;
}
}
和我的映射类:
@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;
}
}
@xmlacessortype(xmlacesstype.FIELD)
@XMLSEEALSE(JaxbExchangeRatesEntry.class)
公共类JAXBEExchangeRatesMap扩展了可打印{
私有静态最终长serialVersionUID=155434567150881L;
@XmlAnyElement
private List entires=new ArrayList();
公共列表getEntires(){
返回实体;
}
公共JAXBEExchangeRatesMap设置项(列表项){
this.entires=entires;
归还这个;
}
}
@XmlAccessorType(XmlAccessType.FIELD)
公共类JAXBEExchangeRateSentry扩展了可打印{
私有静态最终长serialVersionUID=-694282168028218725L;
@XmlAnyElement
私有列表项=新的ArrayList();
公共列表getEntries(){
返回条目;
}
公共JAXBEXchangeSentry设置项(列表项){
this.entries=条目;
归还这个;
}
}
我得到了以下结果:
<?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>
9
7
8
3
1
2
6
4
5
如何删除/跳过rates标记?我建议您按照以下方式构建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>
2015-05-04
1.
0.73788
1.1152
1.35523
1.
1.51136
0.8967
0.66166
1.
您有多个类:
@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;
....
}
@xmlacessortype(xmlacesstype.FIELD)
公共类交换率{
@XmlJavaTypeAdapter(DateAdapter.class)
私人日期;
@xmlement(name=“currency”)
私有列表货币=新的ArrayList();
....
}
@XmlAccessorType(XmlAccessType.FIELD)
公营货币{
@XmlAttribute
私有字符串码;
@xmlement(name=“rate”)
私有列表速率=新的ArrayList();
....
}
@XmlAccessorType(XmlAccessType.FIELD)
公费{
@XmlAttribute
私有字符串码;
@XmlValue
私人双重价值;
....
}
我建议您将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>
2015-05-04
1.
0.73788
1.1152
1.35523
1.
1.51136
0.8967
0.66166
1.
您有多个类:
@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;
....
}
@xmlacessortype(xmlacesstype.FIELD)
公共类交换率{
@XmlJavaTypeAdapter(DateAdapter.class)
私人日期;
@xmlement(name=“currency”)
私有列表货币=新的ArrayList();
....
}
@XmlAccessorType(XmlAccessType.FIELD)
公营货币{
@XmlAttribute
私有字符串码;
@xmlement(name=“rate”)
私有列表速率=新的ArrayList();
....
}
@XmlAccessorType(XmlAccessType.FIELD)
公费{
@XmlAttribute
私有字符串码;
@XmlValue
私人双重价值;
....
}
如果您想保持问题开头所述的原始XML结构,那么使用@XmlJavaTypeAdapter
很难或不可能解决。
但是您可以重用
并将其应用于您的情况:
在ExchRates
类中声明一个用@xmlanyement
注释的列表,以便JAXB将其用于编组/解编组
但是你想要一张地图
或地图
。
(我不知道如何创建CurrencyUnit
s,因此我的解决方案使用String
)
因此您也声明了它,但用@xmltransive
进行了注释,这样JAXB就不会使用它进行编组/解编
最后,在unmarshal(Unmarshaller Unmarshaller,Object parent)之后实现一个私有方法,
,在该方法中,您可以将列表中的内容铲到映射中。
如中所述
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);
}
}
}
如果需要编写XML文件,可能还需要一个私有方法beforeMmarshal(Marshaller-Marshaller)
,将映射中的内容铲回列表。
如中所述
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);
}
}
}
@XmlRootElement(name=“exchangerate”)
@XmlAccess