简单 xml 返回属性字段的 null 值

Simple xml returns null value for attribute field

提问人:opnightfall1771 提问时间:3/26/2019 最后编辑:opnightfall1771 更新时间:10/17/2020 访问量:623

问:

我想使用简单 XML 将以下 XML 反序列化为 POJO:

<shippingInfo>
   <shippingServiceCost currencyId="USD">9.8</shippingServiceCost>
   <shippingType>Flat</shippingType>
   <shipToLocations>Worldwide</shipToLocations>
   <expeditedShipping>true</expeditedShipping>
   <oneDayShippingAvailable>false</oneDayShippingAvailable>
   <handlingTime>3</handlingTime>
</shippingInfo>

为此,我创建了以下类。但是,我遇到了麻烦,因为 currencyId 属性没有正确反序列化。

@Root(name = "shippingInfo")
public class ShippingInfo {

    @Element(name = "shippingServiceCost", required = false)
    private BigDecimal shippingServiceCost;

    @Attribute(name = "currencyId", required = false)
    private String currencyId;

    @Element(name = "shippingType", required = false)
    private String shippingType;

    @Element(name = "shipToLocations" ,required = false)
    private String shipToLocations;

    @Element(name = "expeditedShipping", required = false)
    private Boolean expeditedShipping;

    @Element(name = "oneDayShippingAvailable", required = false)
    private Boolean oneDayShippingAvailable;

    @Element(name = "handlingTime", required = false)
    private Integer handlingTime;

    // Getters & Setters

    public BigDecimal getShippingServiceCost() {
        return shippingServiceCost;
    }

    public void setShippingServiceCost(BigDecimal shippingServiceCost) {
        this.shippingServiceCost = shippingServiceCost;
    }

    public String getCurrencyId() {
        return currencyId;
    }

    public void setCurrencyId(String currencyId) {
        this.currencyId = currencyId;
    }

    public String getShippingType() {
        return shippingType;
    }

    public void setShippingType(String shippingType) {
        this.shippingType = shippingType;
    }

    public String getShipToLocations() {
        return shipToLocations;
    }

    public void setShipToLocations(String shipToLocations) {
        this.shipToLocations = shipToLocations;
    }

    public Boolean isExpeditedShipping() {
        return expeditedShipping;
    }

    public void setExpeditedShipping(Boolean bool) {
        this.expeditedShipping = bool;
    }

    public Boolean isOneDayShippingAvailable() {
        return oneDayShippingAvailable;
    }

    public void setOneDayShippingAvailable(Boolean bool) {
        this.oneDayShippingAvailable = bool;
    }

    public Integer getHandlingTime() {
        return handlingTime;
    }

    public void setHandlingTime(Integer days) {
        this.handlingTime = days;
    }
}

我希望 currencyId 的值在反序列化后为“USD”,但我得到 null。所有元素值似乎都正确反序列化。有人对如何解决这个问题有建议吗?

此外,在以下情况下:

<sellingStatus>
    <currentPrice currencyId="USD">125.0</currentPrice>
    <convertedCurrentPrice currencyId="USD">125.0</convertedCurrentPrice>
    <bidCount>2</bidCount>
    <sellingState>EndedWithSales</sellingState>
</sellingStatus>

如果两个不同的元素上有两个名为 currencyId 的属性,我该如何将它们反序列化为单独的字段?我创建了一个类似的 SellingStatus 类,但不确定如何区分 currencyId 属性。

谢谢!

编辑:根据建议,我尝试将自定义 ShippingServiceCost 类添加到 ShippingInfo,如下所示:

@Element(name = "shippingServiceCost", required = false)
    private ShippingServiceCost shippingServiceCost;

反过来,它看起来像这样:

public class ShippingServiceCost {

    @Element(name = "shippingServiceCost", required = false)
    private BigDecimal shippingServiceCost;

    @Attribute(name = "currencyId", required = false)
    private String currencyId;

    // getters and setters
}

但是当我尝试访问 shippingServiceCost 字段和 currencyId 字段时,我在每个实例中都得到 null(即使我知道有数据)。任何建议将不胜感激。

Java XML 简单框架

评论

0赞 venkat 3/26/2019
从运费信息类中删除 currencyID 属性。为运输服务成本创建一个单独的类,并在其中添加 currencyID 属性。然后,在运费信息类中链接运费类。
0赞 opnightfall1771 3/27/2019
请参阅上面的编辑,我尝试了这个,但我仍然对 shippingServiceCost 和 currencyId 都为 null。
0赞 venkat 3/27/2019
你能用以下“@XmlAccessorType(XmlAccessType.FIELD)”来注释你的shippingServiceCost类吗?
0赞 opnightfall1771 3/27/2019
我试过了这个,但仍然得到空值。

答:

0赞 Danish Faizan 3/26/2019 #1

对于上面的代码,SimpleXML 期望 currencyId 以 .<shippingInfo currencyId="USD">

因此,要解决它,您需要创建另一个名为 ShippingServiceCost 的类,该类将包含 currencyId 属性和 BigDecimal 这也将解决您的第二个查询。您可以通过创建两个类来做到这一点,这两个类将包含 currencyId 属性。CurrentPriceConvertedCurrentPrice

评论

0赞 opnightfall1771 3/26/2019
这实际上是我最初尝试的。但是,当我这样做时,我得到了运输服务成本和货币 ID 的空值。将运输服务成本放在“运输信息”类中解决了这个问题,我现在可以访问它,但我无法获取货币 ID。
0赞 opnightfall1771 3/27/2019
更新:我试过了这个(请参阅编辑到原始帖子),但我仍然得到空值。
0赞 Anwar Mathe 10/17/2020 #2

唯一可行的解决方案是创建一个 Converter 类,请参阅下面的代码:

public class ShippingInfoConverter implements Converter<ShippingInfo> {

@Override
public ShippingInfo read(InputNode inputNode) throws Exception {
    ShippingInfo shippingInfo = new ShippingInfo();
    InputNode shippingServiceCostNode = inputNode.getNext("shippingServiceCost");
    shippingInfo.setShippingServiceCost(new BigDecimal(shippingServiceCostNode.getValue()));
    shippingInfo.setCurrencyId(shippingServiceCostNode.getAttribute("currencyId").getValue());
    shippingInfo.setShippingType(inputNode.getNext("shippingType").getValue());
    shippingInfo.setShipToLocations(inputNode.getNext("shipToLocations").getValue());
    shippingInfo.setExpeditedShipping(Boolean.parseBoolean(inputNode.getNext("expeditedShipping").getValue()));
    shippingInfo.setOneDayShippingAvailable(Boolean.parseBoolean(inputNode.getNext("oneDayShippingAvailable").getValue()));
    shippingInfo.setHandlingTime(Integer.valueOf(inputNode.getNext("handlingTime").getValue()));
    return shippingInfo;
}

@Override
public void write(OutputNode outputNode, ShippingInfo shippingInfo) throws Exception {
    OutputNode shippingServiceCostNode = outputNode.getChild("shippingServiceCost");
    shippingServiceCostNode.setValue(shippingInfo.getShippingServiceCost().toString());
    shippingServiceCostNode.setAttribute("currencyId", shippingInfo.getCurrencyId());
    outputNode.getChild("shippingType").setValue(shippingInfo.getShippingType());
    outputNode.getChild("shipToLocations").setValue(shippingInfo.getShipToLocations());
    outputNode.getChild("expeditedShipping").setValue(Boolean.toString(shippingInfo.isExpeditedShipping()));
    outputNode.getChild("oneDayShippingAvailable").setValue(Boolean.toString(shippingInfo.isOneDayShippingAvailable()));
    outputNode.getChild("handlingTime").setValue(Integer.toString(shippingInfo.getHandlingTime()));
}

}

请注意如何使用节点的 getAttribute 方法设置“currencyId”。

shippingInfo.setCurrencyId(shippingServiceCostNode.getAttribute("currencyId").getValue());

另请注意元素“shippingServiceCost”如何获取属性

shippingServiceCostNode.setAttribute("currencyId", shippingInfo.getCurrencyId());

要让它工作,还需要做一些事情,从你的 POJO 开始

@Root(name = "shippingInfo")
@Convert(ShippingInfoConverter.class)
public class ShippingInfo {

    @Element(name = "shippingServiceCost", required = false)
    private BigDecimal shippingServiceCost;

    private String currencyId;

    @Element(name = "shippingType", required = false)
    private String shippingType;

    @Element(name = "shipToLocations" ,required = false)
    private String shipToLocations;

    @Element(name = "expeditedShipping", required = false)
    private Boolean expeditedShipping;

    @Element(name = "oneDayShippingAvailable", required = false)
    private Boolean oneDayShippingAvailable;

    @Element(name = "handlingTime", required = false)
    private Integer handlingTime;

    // Getters & Setters

    public BigDecimal getShippingServiceCost() {
        return shippingServiceCost;
    }

    public void setShippingServiceCost(BigDecimal shippingServiceCost) {
        this.shippingServiceCost = shippingServiceCost;
    }

    public String getCurrencyId() {
        return currencyId;
    }

    public void setCurrencyId(String currencyId) {
        this.currencyId = currencyId;
    }

    public String getShippingType() {
        return shippingType;
    }

    public void setShippingType(String shippingType) {
        this.shippingType = shippingType;
    }

    public String getShipToLocations() {
        return shipToLocations;
    }

    public void setShipToLocations(String shipToLocations) {
        this.shipToLocations = shipToLocations;
    }

    public Boolean isExpeditedShipping() {
        return expeditedShipping;
    }

    public void setExpeditedShipping(Boolean bool) {
        this.expeditedShipping = bool;
    }

    public Boolean isOneDayShippingAvailable() {
        return oneDayShippingAvailable;
    }

    public void setOneDayShippingAvailable(Boolean bool) {
        this.oneDayShippingAvailable = bool;
    }

    public Integer getHandlingTime() {
        return handlingTime;
    }

    public void setHandlingTime(Integer days) {
        this.handlingTime = days;
    }

}

添加下面的行将 SimpleXML 指向转换器类

@Convert(ShippingInfoConverter.class)

另一个变化是删除@Attribute注释。 最后一件事是驱动程序类需要启用 AnnotationStrategy 序列化和反序列化对象时。

Serializer serializer = new Persister(new AnnotationStrategy());