首页 > 解决方案 > 使用 JAXB 编组 XML 元素内的属性

问题描述

我使用 Spring JPA 并拥有以下实体:

@Entity
@Table(name = Constants.ENTITY_TABLE_PREFIX + "ENTRY")
@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement(name = "monObj_info")
public class EntryXML implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "ID")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @XmlAttribute
    private long id;

    @Column(name = "ip_address", nullable = true)
    @XmlElement
    private String ip_address;

    @Column(name = "network_element_name", nullable = false)
    @XmlElement
    private String network_element_name;

    public EntryXML() {}

    public EntryXML(long id, String ip_address, String   network_element_name) {
        super();
        this.id = id;
        this.ip_address = ip_address;
        this.network_element_name = network_element_name;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getIp_address() {
        return ip_address;
    }

    public void setIp_address(String ip_address) {
        this.ip_address = ip_address;
    }

    public String getNetwork_element_name() {
        return network_element_name;
    }

    public void setNetwork_element_name(String network_element_name) {
        this.network_element_name = network_element_name;
    }

}

和端点:

@RestController
public class EntryXMLEndpoint {

    @Autowired
    private IEntryXMLService service;

    @RequestMapping(value = "/restxml", produces = { "application/xml" })
    public EntryXML findEntries() {
        EntryXML record = service.findById(1);
        return record;
    }

}

现在请求的响应是:

<monObj_info id="1">
 <atribute name="ip_address" value="xx.xxx.xxx.x"/>
 <atribute name="network_element_name" value="xxxxxx"/>
</monObj_info>

当然我得到的是:

<monObj_info id="1">
  <ip_address>xx.xxx.xxx.x</ip_address>
  <network_element_name>xxxxxx</network_element_name>
</monObj_info>

我读过类似的帖子,但问题是我无法在我的实体类中创建一个包含所需元素的列表,因为它不会映射到相应表中的任何列,有什么建议吗?

标签: springjaxbspring-data-jpa

解决方案


你可以用一种直截了当但有点老套的方式来实现你的目标。

由于您不希望直接对ip_addressandnetwork_element_name属性进行编组和解组,因此您需要删除它们的@XmlElement注释并添加@XmlTransient.

相反,您希望对一些<atribute name="..." value="..." />元素进行编组和解组。因此,您需要在EntryXML类中添加以下内容:

  • 包含attributes属性列表的属性。它带有注释,@XmlElement因此它将成为 XML 编组和解组的一部分。它带有注释,@Transient因此它不会成为数据库持久性的一部分。
  • 一个简单的帮助类Attribute,用于保存名称和值。 namevalue带有注释,@XmlAttribute以便它们成为 XML 编组和解组的一部分。
  • 一个Marshal 事件回调beforeMarshal),用于ip_addressnetwork_element_name 列表之间进行转换attributes
  • 用于执行相反转换的Unmarshal 事件回调( afterUnmarshal )。

@XmlElement(name = "atribute")
@Transient  // from package javax.persistence
private List<Attribute> attributes;

// there is no need for getAttributes and setAttributes methods

private static class Attribute {

    @SuppressWarnings("unused")  // called by the unmarshaller
    Attribute() {
    }

    Attribute(String name, String value) {
        this.name = name;
        this.value = value;
    }

    @XmlAttribute
    private String name;

    @XmlAttribute
    private String value;
}

@SuppressWarnings("unused") // this method is called only by the marshaller
private boolean beforeMarshal(Marshaller marshaller) {
    attributes = new ArrayList<>();
    attributes.add(new Attribute("ip_address", ip_address));
    attributes.add(new Attribute("network_element_name", network_element_name));
    return true;
}

@SuppressWarnings("unused") // this method is called only by the unmarshaller
private void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {
    if (attributes != null) {
        for (Attribute attribute : attributes) {
            switch (attribute.name) {
            case "ip_address":
                ip_address = attribute.value;
                break;
            case "network_element_name":
                network_element_name = attribute.value;
                break;
            }
        }
    }
}

然后 XML 输出将如下所示:

<monObj_info id="1">
    <atribute name="ip_address" value="xx.xxx.xxx.x"/>
    <atribute name="network_element_name" value="xxxxxx"/>
</monObj_info>

推荐阅读