ITKeyword,专注技术干货聚合推荐

注册 | 登录

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

234390216 分享于

2020腾讯云双十一活动,全年最低!!!(领取3500元代金券),
地址https://cloud.tencent.com/act/cps/redirect?redirect=1073

2020阿里云最低价产品入口,含代金券(新老用户有优惠),
地址https://www.aliyun.com/minisite/goods

推荐:Linq To XML:用名称查找元素

XElement firstParticipant; // A full document with all the bells and whistles. XDocument xDocument = new XDocument( new XDeclaration("1.0", "UTF-8", "

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代码如下。 @Testpublic 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 getProvi

推荐:jaxb jaxp使用xml来生成动态页面 - xml xsd xsl ( xpath xslt ) css 概念入门

问题: 公司里面的一个项目需要建立一个Test Benchmark 来比较不同算法计算的mileage。

需求定义: 输入:预先收集的一套Test case,可以通过页面添加新的Test

nce() {

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类。其它的保持不变。 @Testpublic 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;

}

}@XmlRegistrypublic class ObjectFactory {

@XmlElementDecl(name="address")

public JAXBElement<Address> createAddress() {

return null;

}

} 上面的ObjectFactory的createAddress()方法是一个空实现,直接返回了null。实际上该方法主要用来作为JAXB的一个规范使用的,主要是用来定义XmlElementDecl的。当然了,如果有需要你也可以在其中定义创建对象的真实逻辑,该方法也可以接收参数。 在创建对应的JAXBContext时加上我们所使用的ObjectFactory.class。 @Testpublic 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> (完)

推荐:JAXB(五)——处理动态元素或属性

处理动态元素或属性 动态元素 假设现在有一项解析XML的需求,该XML的大体结构是固定的,如下这样: <response> <errorCode></errorCode> <errorMessag

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

相关阅读排行


相关内容推荐

最新文章

×

×

请激活账号

为了能正常使用评论、编辑功能及以后陆续为用户提供的其他产品,请激活账号。

您的注册邮箱: 修改

重新发送激活邮件 进入我的邮箱

如果您没有收到激活邮件,请注意检查垃圾箱。