`
234390216
  • 浏览: 10232925 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
博客专栏
A5ee55b9-a463-3d09-9c78-0c0cf33198cd
Oracle基础
浏览量:462622
Ad26f909-6440-35a9-b4e9-9aea825bd38e
springMVC介绍
浏览量:1775515
Ce363057-ae4d-3ee1-bb46-e7b51a722a4b
Mybatis简介
浏览量:1398353
Bdeb91ad-cf8a-3fe9-942a-3710073b4000
Spring整合JMS
浏览量:395022
5cbbde67-7cd5-313c-95c2-4185389601e7
Ehcache简介
浏览量:679982
Cc1c0708-ccc2-3d20-ba47-d40e04440682
Cas简介
浏览量:530892
51592fc3-854c-34f4-9eff-cb82d993ab3a
Spring Securi...
浏览量:1183946
23e1c30e-ef8c-3702-aa3c-e83277ffca91
Spring基础知识
浏览量:467911
4af1c81c-eb9d-365f-b759-07685a32156e
Spring Aop介绍
浏览量:151388
2f926891-9e7a-3ce2-a074-3acb2aaf2584
JAXB简介
浏览量:68151
社区版块
存档分类
最新评论

JAXB(六)——动态指定XML元素名称

    博客分类:
  • JAXB
阅读更多

JAXB动态指定生成的XML元素名称

通常我们在使用JAXB生成XML时,都是通过@XmlRootElement@XmlElement事先指定对应的类型的对象在生成XML时生成的元素的名称。比如下面这样。

@XmlRootElement(name="person")
@XmlType(propOrder = { "id", "name", "age", "address" })
public class Person {
    private Integer id;
    private String name;
    private Integer age;
    private Address address;

    @XmlAttribute(name = "id")
    public Integer getId() {
       return id;
    }

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

    @XmlAttribute
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
    
}

@XmlType(propOrder = { "province", "city", "area", "other" })
public class Address {
    private Integer id;
    private String province;
    private String city;
    private String area;
    private String other;

    @XmlAttribute(name = "id")
    public Integer getId() {
        return id;
    }

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

    public String getProvince() {
        return province;
    }

    public void setProvince(String province) {
        this.province = province;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getArea() {
        return area;
    }

    public void setArea(String area) {
        this.area = area;
    }

    public String getOther() {
        return other;
    }

    public void setOther(String other) {
        this.other = other;
    }
}

对应的输出结果是如下这样,这样的结果大家都已经很熟悉了。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person id="1" name="张三">
    <age>30</age>
    <address id="1">
        <province>广东省</province>
        <city>深圳市</city>
        <area>南山区</area>
        <other>其它</other>
    </address>
</person>

动态生成根节点元素名称

那如果现在业务上有这样一项需求,Person类对应的根节点元素的名称需要是动态的,某些业务场景下是person1,某些业务场景下是person2、person3等这应该怎么办呢?这个时候我们应该把我们的对象转换为一个JAXBElement对象,JAXB在把JAXBElement类型的对象转换为XML时会调用它的getName()方法获取对应的元素的名称。我们把Person类改造一下,新增一个elementName属性,用于指定动态的节点名称,即生成的根节点的名称将以该属性值为准,同时该属性不属于Person类对应XML元素的子元素的一部分,所以需要加上@XmlTransient。

@XmlType(propOrder={"id", "name", "age", "address"})
public class Person {
    private Integer id;
    private String name;
    private Integer age;
    private Address address;
    /**
     * 用来指定对应的根节点的名称
     */
    private String elementName;
    
    @XmlAttribute(name = "id")
    public Integer getId() {
       return id;
    }

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

    @XmlAttribute
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    /**
     * 该属性主要用来指定对象的根节点名称,不需要作为对应转换为XML的一个元素,所以需要使用@XmlTransient标注
     * @return
     */
    @XmlTransient
    public String getElementName() {
        return elementName;
    }

    public void setElementName(String elementName) {
        this.elementName = elementName;
    }
    
}

然后在生成XML时把Person对象使用JAXBElement对象包裹起来,marshal的对象也由Person对象变为包裹了Person对象的JAXBElement对象,所以这时候的marshal代码如下。

@Test
public void testMarshal() throws JAXBException {
    JAXBContext context = JAXBContext.newInstance(Person.class, ObjectFactory.class);
    Marshaller marshaller = context.createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    StringWriter writer = new StringWriter();
    //构造Person对象,不是本文的重点
    Person person = this.buildPerson();
    //这里可以根据业务需要动态的指定元素的名称
    person.setElementName("person1");

    String eleName = person.getElementName();
    QName name = new QName(eleName);
    JAXBElement<Person> personEle = new JAXBElement<>(name, Person.class, person);
    
    marshaller.marshal(personEle, writer);
    System.out.println(writer.toString());
    
}

生成的XML如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person1 id="1" name="张三">
    <age>30</age>
    <address id="1">
        <province>广东省</province>
        <city>深圳市</city>
        <area>南山区</area>
        <other>其它</other>
    </address>
</person1>

这个时候Person类上的@XmlRootElement已经不起作用了,可有可无,因为XML元素名称已经不由它来指定了,但是属性上的@XmlAttribute@XmlElement还是会起作用的。

动态生成非根节点元素名称

如果上面的Person类的Address属性也有动态节点的需求,也是根据某种业务规则需要生成address1、address2等节点名称,这个时候又该怎么做呢?你会不会觉得这很简单,我把对应的属性定义为JAXBElement类型即可,像如下这样子。

@XmlType(propOrder={"id", "name", "age", "address"})
public class Person {
    private Integer id;
    private String name;
    private Integer age;
    private JAXBElement<Address> address;
    /**
     * 用来指定对应的根节点的名称
     */
    private String elementName;
    
    @XmlAttribute(name = "id")
    public Integer getId() {
       return id;
    }

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

    @XmlAttribute
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public JAXBElement<Address> getAddress() {
        return address;
    }

    public void setAddress(JAXBElement<Address> address) {
        this.address = address;
    }

    /**
     * 该属性主要用来指定对象的根节点名称,不需要作为对应转换为XML的一个元素,所以需要使用@XmlTransient标注
     * @return
     */
    @XmlTransient
    public String getElementName() {
        return elementName;
    }

    public void setElementName(String elementName) {
        this.elementName = elementName;
    }
    
}

然后在Address类中也增加一个elementName属性用于指定动态的节点名称。

@XmlType(propOrder = { "province", "city", "area", "other" })
public class Address {
    private Integer id;
    private String province;
    private String city;
    private String area;
    private String other;
    /**
     * 用来指定根节点名称
     */
    private String elementName;

    @XmlAttribute(name = "id")
    public Integer getId() {
        return id;
    }

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

    public String getProvince() {
        return province;
    }

    public void setProvince(String province) {
        this.province = province;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getArea() {
        return area;
    }

    public void setArea(String area) {
        this.area = area;
    }

    public String getOther() {
        return other;
    }

    public void setOther(String other) {
        this.other = other;
    }

    @XmlTransient
    public String getElementName() {
        return elementName;
    }

    public void setElementName(String elementName) {
        this.elementName = elementName;
    }
    
}

在构造Person对象时,把构造的Address对象用JAXBElement对象包起来再赋给Person对象。

private Person buildPerson() {
    Person person = new Person();
    person.setId(1);
    person.setName("张三");
    person.setAge(30);
    Address address = new Address();
    address.setId(1);
    address.setProvince("广东省");
    address.setCity("深圳市");
    address.setArea("南山区");
    address.setOther("其它");
    //这里可以根据业务需要动态的指定元素的名称
    address.setElementName("address1");
    QName name = new QName(address.getElementName());
    JAXBElement<Address> addressEle = new JAXBElement<>(name, Address.class, address);
    person.setAddress(addressEle);
    return person;
}

在进行marshal创建JAXBContext时需要加入Address.class,不然在marshal时将不识别Address类。其它的保持不变。

@Test
public void testMarshal() throws JAXBException {
    JAXBContext context = JAXBContext.newInstance(Person.class, Address.class);
    Marshaller marshaller = context.createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    StringWriter writer = new StringWriter();
    //构造Person对象,不是本文的重点
    Person person = this.buildPerson();
    //这里可以根据业务需要动态的指定元素的名称
    person.setElementName("person1");

    String eleName = person.getElementName();
    QName name = new QName(eleName);
    JAXBElement<Person> personEle = new JAXBElement<>(name, Person.class, person);
    
    marshaller.marshal(personEle, writer);
    System.out.println(writer.toString());
    
}

这时候生成的XML如下所示。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person1 id="1" name="张三">
    <age>30</age>
    <address>
        <nil>false</nil>
        <value xsi:type="address" id="1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <province>广东省</province>
            <city>深圳市</city>
            <area>南山区</area>
            <other>其它</other>
        </value>
    </address>
</person1>

其实这也很好理解,JAXB把JAXBElement当作一个普通的Java类来处理了,其中拥有setNil()和isNil()方法,所以会产生一个nil节点;它也拥有getValue()和setValue()的方法,所以产生了value节点;value节点的真实Java类型是Address类型,所以value节点的子节点都是按照Address类的结构来生成的;至于value节点上的namespace信息是因为Address类没有直接跟根节点对应的类Person产生关联,所以需要额外的信息来声明。显然,这与我们期望的结果是不一样的,我们本来期望的是得到如下这样的内容。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person1 id="1" name="张三">
    <age>30</age>
    <address1 id="1">
        <province>广东省</province>
        <city>深圳市</city>
        <area>南山区</area>
        <other>其它</other>
    </address1>
</person1>

那需要如何才能得到我们想要的结果呢?这时候就需要应用@XmlRegistry、@XmlElementDecl和@XmlElementRef了。

  • XmlRegistry注解用来标注在类上面,表示该类中包含有使用@XmlElementDecl标注的方法。
  • XmlElementDecl注解用来标注在方法上,该方法可以接收参数,但需要有返回类型。它又需要与@XmlElementRef一起使用。XmlElementDecl在使用时必须指定一个name属性,namespace属性也可以指定,以唯一的确定这样一个XmlElementDecl的声明。
  • 我们可以通过XmlElementRef来指定当前的XML和对象之间的映射需要使用的是哪个XmlElementDecl指定的方法,这是通过其name属性和namespace属性来指定的,它们的值必须与对应的XmlElementDecl上声明的name和namespace一致。

当我们的一个属性声明为JAXBElement形式,我们希望它生成的XML形式是以JAXBElement中包含的那个具体的对象为准,而不是以JAXBElement自己为准时,我们可以在该属性上使用@XmlElementRef标注,同时指向创建它的ObjectFactory的对应方法上标注的@XmlElementDecl,同时需要注意在ObjectFactory类上采用@XmlRegistry进行标注。然后在转换XML时,还需要指定使用的Class除了当前的对象外,还包括对应的ObjectFactory类。所以针对上面的需求,我们可以改为如下配置即可。

@XmlType(propOrder={"id", "name", "age", "address"})
public class Person {
    private Integer id;
    private String name;
    private Integer age;
    private JAXBElement<Address> address;
    /**
     * 用来指定对应的根节点的名称
     */
    private String elementName;
    
    @XmlAttribute(name = "id")
    public Integer getId() {
       return id;
    }

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

    @XmlAttribute
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @XmlElementRef(name="address")
    public JAXBElement<Address> getAddress() {
        return address;
    }

    public void setAddress(JAXBElement<Address> address) {
        this.address = address;
    }

    /**
     * 该属性主要用来指定对象的根节点名称,不需要作为对应转换为XML的一个元素,所以需要使用@XmlTransient标注
     * @return
     */
    @XmlTransient
    public String getElementName() {
        return elementName;
    }

    public void setElementName(String elementName) {
        this.elementName = elementName;
    }
    
}
@XmlRegistry
public class ObjectFactory {

    @XmlElementDecl(name="address")
    public JAXBElement<Address> createAddress() {
        return null;
    }
    
}

上面的ObjectFactory的createAddress()方法是一个空实现,直接返回了null。实际上该方法主要用来作为JAXB的一个规范使用的,主要是用来定义XmlElementDecl的。当然了,如果有需要你也可以在其中定义创建对象的真实逻辑,该方法也可以接收参数。

在创建对应的JAXBContext时加上我们所使用的ObjectFactory.class。

@Test
public void testMarshal() throws JAXBException {
    JAXBContext context = JAXBContext.newInstance(Person.class, ObjectFactory.class);
    Marshaller marshaller = context.createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    StringWriter writer = new StringWriter();
    //构造Person对象,不是本文的重点
    Person person = this.buildPerson();
    //这里可以根据业务需要动态的指定元素的名称
    person.setElementName("person1");

    String eleName = person.getElementName();
    QName name = new QName(eleName);
    JAXBElement<Person> personEle = new JAXBElement<>(name, Person.class, person);
    
    marshaller.marshal(personEle, writer);
    System.out.println(writer.toString());
    
}

应用上面的测试代码,最终的生成结果是如下这样的,这就达到了我们的期望。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person1 id="1" name="张三">
    <age>30</age>
    <address1 id="1">
        <province>广东省</province>
        <city>深圳市</city>
        <area>南山区</area>
        <other>其它</other>
    </address1>
</person1>

(完)

0
0
分享到:
评论

相关推荐

    JAVA JAXB 解析XML嵌套子节点为字符串

    在Java开发中,JAXB(Java Architecture for XML Binding)是一个标准的API,用于将XML文档与Java对象之间进行互相转换。这个技术对于处理XML数据,尤其是解析和生成XML文档非常有用。当我们面临XML文档中存在嵌套子...

    jaxb生成XML例子

    这意味着JAXB将创建一个名为`&lt;DetailList&gt;`的XML元素,其中包含多个`&lt;detail&gt;`子元素,这些元素分别对应`Detail`类的实例。 总结起来,JAXB通过注解提供了一种简单的方法来控制Java对象如何被转换为XML,以及XML...

    利用JAXB进行xml和javabean之间转换

    JAXB通过元数据(如注解或XML绑定文件)来映射Java类到XML元素,以及XML元素到Java类。这使得XML文档能够被自动解析成Java对象,反之亦然。 **1. JAXB的使用步骤** (1) **创建Java类(javabean)** 首先,定义一...

    stax+jaxb进行xml解析

    - 为XML元素创建对应的Java类,并使用JAXB的注解如@XmlRootElement、@XmlElement等来标记属性与XML元素之间的映射关系。 - 可以使用@XmlAccessorType注解来指定字段或属性的默认绑定规则。 3. **JAXB解析和序列化...

    JAXB_Java Architecture For XML Binding

    Java Architecture for XML Binding (JAXB) 是Java平台上的一个标准技术,它允许程序开发者将XML文档与Java对象之间进行绑定,实现XML数据的序列化和反序列化。JAXB是Java SE和Java EE环境中的一部分,提供了高效且...

    jaxb解析xml

    JAXB 解析 XML JAXB (Java Architecture for XML Binding) 是一种基于 Java 的 XML 绑定技术,主要功能是根据 DTD 或者 XML Schema 将 XML Element 转化为 Java 类。JAXB 将 XML 文本流转化为 Java Object,把 XML ...

    jaxb (XML操作)

    **JAXB(Java Architecture for XML Binding)** 是Java平台中用于处理XML的一种强大的工具,它提供了将XML文档与Java对象之间的映射,从而方便XML数据的解析和生成。通过JAXB,开发者可以轻松地实现XML数据到Java...

    使用jaxb根据xsd生成xml文档

    **使用JAXB根据XSD生成XML文档** 在Java开发中,XML文档的生成与解析是一项常见的任务,特别是在处理数据交换和存储时。JAXB(Java Architecture for XML Binding)是Java平台标准的一部分,它提供了一种将Java对象...

    Android支持JAXB(Java Architecture for XML Binding)

    Android支持JAXB(Java Architecture for XML Binding) JAXB(Java Architecture for XML Binding)是Java领域中的一项标准技术,能够根据XML Schema生成Java类,并将XML实例文档反向生成Java对象树。JAXB提供了将...

    通过JAXB实现完成java对象和xml的互相转换

    在上述代码中,`@XmlRootElement`注解告诉JAXB`Person`类是XML文档的根元素,而`name`和`age`字段被映射为XML元素。 要将Java对象序列化为XML,我们可以使用`JAXBContext`和`Marshaller`: ```java Person person ...

    最新JAXB解析XML教程

    **JAXB(Java Architecture for XML Binding)**是Java平台上的一个标准API,它允许开发者将XML文档和Java对象之间进行绑定,实现XML数据的编解码。JAXB为开发人员提供了一种简单、高效的方式,使得在Java应用程序中...

    JAXB工具类 xml转为java对象 java对象转为xml

    Java Architecture for XML Binding (JAXB) 是Java平台中用于处理XML和Java对象之间转换的一个标准API。它使得在Java应用程序中使用XML数据变得更加方便,无需手动编写大量的转换代码。本教程将详细介绍JAXB如何实现...

    JAXB-XML注解

    它有三个属性:name、propOrder、namespace,其中 name 属性指定了 XML 元素的名称,propOrder 属性指定了 Java 对象的属性顺序,namespace 属性指定了 XML 元素的命名空间。 例如: ```java @XmlType(name = ...

    用JAXB生成一个XML

    ### 使用JAXB生成XML文档详解 #### 一、前言 在现代软件开发过程中,XML(可扩展标记语言)作为一种重要的数据交换格式,被广泛应用于各种应用场景中。特别是在J2EE(Java Platform, Enterprise Edition)领域,...

    jaxb xml 转map

    在Java世界中,JAXB(Java Architecture for XML Binding)是一个标准的API,用于将XML文档与Java对象之间进行互相转换。这个过程被称为对象绑定。在处理XML数据时,JAXB提供了一种方便的方式,让我们可以将XML数据...

    [转载] JAXB中Java对象和XML之间的转换

    JAXB允许我们将Java类与XML Schema定义的元素和类型绑定,从而实现XML的序列化和反序列化。 在Java对象和XML之间的转换过程中,JAXB主要涉及到以下几个关键概念: 1. **Java类与XML Schema绑定**: JAXB使用`@...

    Jaxb2 实现JavaBean与xml互转

    例如,我们可以使用`@XmlRootElement`标记类为XML根元素,`@XmlElement`指定字段对应的XML元素: ```java @XmlRootElement(name = "person") public class Person { @XmlElement(name = "name") private String ...

    JAXB 生成XML文件

    2. **注解**:在描述中提到的"JAXB注解"是用于标记Java类和类成员的关键元素,以指示它们如何在XML中表示。例如,`@XmlRootElement`注解标识一个类作为XML文档的根元素,`@XmlElement`注解用于将类的属性映射到XML...

    webservice之使用jaxb把xml转换Object或把对象转换成xml文件

    1. 自动映射:JAXB可以自动将XML元素和属性映射到Java类的字段,减少了手动编写代码的工作量。 2. 高效性:由于JAXB是JDK内置的,因此性能相对较高,适合处理大量XML数据。 3. WebService:在开发基于SOAP的...

Global site tag (gtag.js) - Google Analytics