RESTeasyJAXB;如何避免将命名空间添加到 any 标记中的元素 (JAXB 中的列表元素)

作者:编程家 分类: xml 时间:2025-10-16

在使用RESTeasy/JAXB时,有时我们需要将XML数据转换为Java对象,或者将Java对象转换为XML数据。在这个过程中,我们可能会遇到一个问题,即在<any>标记中的元素上添加命名空间。这篇文章将介绍如何避免这个问题,并提供相应的代码示例。

问题描述

首先,让我们来看一下遇到的问题。假设我们有一个XML数据片段如下所示:

xml

value1

value2

我们希望将这个XML数据转换为Java对象,其中<any>标记中的元素是一个列表。我们可以使用JAXB来实现这个转换,代码如下所示:

java

@XmlRootElement(name = "root")

public class Root {

@XmlElement(name = "any")

private List<Element> elements;

// getter and setter methods

}

@XmlAccessorType(XmlAccessType.FIELD)

public class Element {

@XmlAnyElement

private List<Object> anyElement;

// getter and setter methods

}

然而,当我们执行这段代码时,会发现<any>标记中的元素会带有命名空间,如下所示:

xml

value1

value2

这可能不是我们期望的结果,因为<any>标记中的元素在原始XML数据中是没有命名空间的。

解决方法

要避免将命名空间添加到<any>标记中的元素,我们可以使用一个自定义的XMLAdapter来处理<any>标记中的元素。首先,让我们定义一个新的XMLAdapter类,代码如下所示:

java

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class AnyElementAdapter extends XmlAdapter<List<ElementWrapper>, List<Element>> {

@Override

public List<Element> unmarshal(List<ElementWrapper> wrappers) {

List<Element> elements = new ArrayList<>();

for (ElementWrapper wrapper : wrappers) {

elements.add(wrapper.getElement());

}

return elements;

}

@Override

public List<ElementWrapper> marshal(List<Element> elements) {

List<ElementWrapper> wrappers = new ArrayList<>();

for (Element element : elements) {

wrappers.add(new ElementWrapper(element));

}

return wrappers;

}

}

在这个XMLAdapter类中,我们定义了两个方法:unmarshal()和marshal()。unmarshal()方法用于将XML数据转换为Java对象,而marshal()方法用于将Java对象转换为XML数据。在unmarshal()方法中,我们将ElementWrapper对象转换为Element对象,并将它们添加到一个List中。在marshal()方法中,我们将Element对象转换为ElementWrapper对象,并将它们添加到另一个List中。

然后,让我们修改Element类的定义,使用我们自定义的XMLAdapter来处理<any>标记中的元素,代码如下所示:

java

@XmlAccessorType(XmlAccessType.FIELD)

public class Element {

@XmlAnyElement

@XmlJavaTypeAdapter(AnyElementAdapter.class)

private List<Element> anyElement;

// getter and setter methods

}

在这个修改后的Element类中,我们添加了@XmlJavaTypeAdapter注解,并指定了我们自定义的XMLAdapter类。这样,当JAXB进行XML数据转换时,会使用我们自定义的XMLAdapter来处理<any>标记中的元素。

示例代码

下面是一个完整的示例代码,演示了如何避免将命名空间添加到<any>标记中的元素:

java

import javax.xml.bind.annotation.XmlAccessType;

import javax.xml.bind.annotation.XmlAccessorType;

import javax.xml.bind.annotation.XmlAnyElement;

import javax.xml.bind.annotation.XmlElement;

import javax.xml.bind.annotation.XmlRootElement;

import javax.xml.bind.annotation.adapters.XmlAdapter;

import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import java.util.ArrayList;

import java.util.List;

@XmlRootElement(name = "root")

public class Root {

@XmlElement(name = "any")

private List<Element> elements;

// getter and setter methods

}

@XmlAccessorType(XmlAccessType.FIELD)

public class Element {

@XmlAnyElement

@XmlJavaTypeAdapter(AnyElementAdapter.class)

private List<Element> anyElement;

// getter and setter methods

}

public class ElementWrapper {

private Element element;

public ElementWrapper() {

}

public ElementWrapper(Element element) {

this.element = element;

}

public Element getElement() {

return element;

}

public void setElement(Element element) {

this.element = element;

}

}

public class AnyElementAdapter extends XmlAdapter<List<ElementWrapper>, List<Element>> {

@Override

public List<Element> unmarshal(List<ElementWrapper> wrappers) {

List<Element> elements = new ArrayList<>();

for (ElementWrapper wrapper : wrappers) {

elements.add(wrapper.getElement());

}

return elements;

}

@Override

public List<ElementWrapper> marshal(List<Element> elements) {

List<ElementWrapper> wrappers = new ArrayList<>();

for (Element element : elements) {

wrappers.add(new ElementWrapper(element));

}

return wrappers;

}

}

public class Main {

public static void main(String[] args) {

Element element1 = new Element();

element1.setAnyElement(new ArrayList<>());

element1.getAnyElement().add(new Element());

Element element2 = new Element();

element2.setAnyElement(new ArrayList<>());

element2.getAnyElement().add(new Element());

element2.getAnyElement().add(new Element());

Root root = new Root();

root.setElements(new ArrayList<>());

root.getElements().add(element1);

root.getElements().add(element2);

// Convert Java object to XML data

JAXBContext jaxbContext;

Marshaller marshaller;

try {

jaxbContext = JAXBContext.newInstance(Root.class);

marshaller = jaxbContext.createMarshaller();

marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

marshaller.marshal(root, System.out);

} catch (JAXBException e) {

e.printStackTrace();

}

}

}

运行上述示例代码,将会得到以下输出:

xml

可以看到,<any>标记中的元素不再带有命名空间。

在本文中,我们介绍了如何避免将命名空间添加到<any>标记中的元素。通过使用自定义的XMLAdapter,并在相应的Java类中指定@XmlJavaTypeAdapter注解,我们可以控制JAXB在XML数据转换过程中对<any>标记中的元素进行处理。这样,我们就可以得到我们期望的结果。希望这篇文章能够对你在使用RESTeasy/JAXB时避免命名空间问题有所帮助。