Jaxb:在同一个包中解组具有多个命名空间的 xml
Posted
技术标签:
【中文标题】Jaxb:在同一个包中解组具有多个命名空间的 xml【英文标题】:Jaxb: Unmarshalling xml with multiple namespaces in same package 【发布时间】:2013-03-24 05:47:26 【问题描述】:我是在 xml 中使用命名空间的新手,所以我有点困惑,想澄清一下。我有一个 java 服务,我正在接收具有许多不同名称空间的 xml 文档,当我让它工作时,我觉得我一定做错了什么,所以我想检查一下。在我的 package-info.java 中,我有我的模式注释,例如:
@javax.xml.bind.annotation.XmlSchema(
xmlns=
@javax.xml.bind.annotation.XmHS(prefix="train", namespaceURI="http://mycompany/train"),
@javax.xml.bind.annotation.XmHS(prefix="passenger", namespaceURI="http://mycompany/passenger")
,
elementFormDefault = javax.xml.bind.annotation.XmlNsForm=QUALIFIED
)
我有一个在类级别注释的 Train.java:
@XmlRootElement(name="Train", namespace="http://mycompany/train")
类中的每个字段都用以下注释:
@XmlElement(name="Color") for example
Train 包含一个乘客列表,因此有一个属性
private Set<Passenger> passengers;
并且这个集合带有注释:
@XmlElementWrapper(name="Passengers")
@XmlElements(@XmlElement(name="Passenger", namespace="http://mycompany/passenger"))
然后在Passenger.java中,类本身被注释为:
@XmlElement(name="Passenger", namespace="http://mycompany/passenger")
最后对于Passenger.java中的各个字段,它们的注释是这样的:
@XmlElement(name="TicketNumber", namespace="http://mycompany/passenger")
所以当我有一个看起来像这样的 xml 时:
<train:Train>
<train:Color>Red</train:Color>
<train:Passengers>
<train:Passenger>
<passenger:TicketNumber>T101</passenger:TicketNumber>
</train:Passenger>
</train:Passengers>
</train:Train>
现在我解组收到的这个 xml,并设置了 Train 的 Color 属性和Passenger 的 TicketNumber 属性。但我不知道为什么我需要在 TicketNumber 上的 XmlElement 注释上添加命名空间 url 才能使其工作,但我不需要为 Train 上的 Color 属性这样做。如果我从 TicketNumber 上的 XmlElement 注释中删除命名空间属性,则 xml 中的值不会映射到对象,除非我也从 xml 请求中删除命名空间前缀。我觉得因为我已经在 XmlRootElement 上为乘客定义了命名空间属性,所以我不需要为类中的每个字段都这样做,就像我不需要为火车一样,所以我假设我一定是设置有问题。有人可以指出我正确的方向吗?谢谢!
【问题讨论】:
【参考方案1】:下面是根据您的模型解释命名空间在JAXB (JSR-222) 中的工作方式。
JAVA 模型
包裹信息
以下是您的 @XmlSchema
注释的修改版本。它包含一些关键信息:
namespace
- 默认命名空间,将用于限定未指定其他命名空间的全局元素(对应于 @XmlRootElement
和 @XmlElementDecl
注释(以及基于 elementFormDefault
值的本地元素)的元素。李>
elementFormDefault
默认情况下,只有全局元素是命名空间限定的,但通过将值设置为 XmlNsForm.QUALIFIED
,所有未指定显式命名空间的元素都将使用 namespace
值限定。
xmlns
是 JAXB 实现应该为这些命名空间使用的首选前缀集(尽管它们可能使用其他前缀)。
@XmlSchema(
namespace="http://mycompany/train",
elementFormDefault = XmlNsForm.QUALIFIED,
xmlns=
@XmlNs(prefix="train", namespaceURI="http://mycompany/train"),
@XmlNs(prefix="passenger", namespaceURI="http://mycompany/passenger")
)
package forum15772478;
import javax.xml.bind.annotation.*;
训练
由于Train
类对应的所有元素都对应@XmlSchema
注解上指定的namespace
,所以我们不需要指定任何命名空间信息。
@XmlRootElement
注释对应于全局元素。
本地元素 - @XmlElementWrapper
和 @XmlElement
注释对应于本地元素。
package forum15772478;
import java.util.List;
import javax.xml.bind.annotation.*;
@XmlRootElement(name="Train")
public class Train
private List<Passenger> passengers;
@XmlElementWrapper(name="Passengers")
@XmlElement(name="Passenger")
public List<Passenger> getPassengers()
return passengers;
public void setPassengers(List<Passenger> passengers)
this.passengers = passengers;
乘客
如果与Passenger
类上的属性对应的所有元素都将在http://mycompany/passenger
命名空间中,那么您可以使用@XmlType
注释覆盖@XmlSchema
注释中的namespace
。
package forum15772478;
import javax.xml.bind.annotation.*;
@XmlType(namespace="http://mycompany/passenger")
public class Passenger
private String ticketNumber;
@XmlElement(name="TicketNumber")
public String getTicketNumber()
return ticketNumber;
public void setTicketNumber(String ticketNumber)
this.ticketNumber = ticketNumber;
或者,您可以在属性级别覆盖命名空间。
package forum15772478;
import javax.xml.bind.annotation.*;
public class Passenger
private String ticketNumber;
@XmlElement(
namespace="http://mycompany/passenger",
name="TicketNumber")
public String getTicketNumber()
return ticketNumber;
public void setTicketNumber(String ticketNumber)
this.ticketNumber = ticketNumber;
演示代码
可以运行以下演示代码来证明一切正常:
演示
package forum15772478;
import java.io.File;
import javax.xml.bind.*;
public class Demo
public static void main(String[] args) throws Exception
JAXBContext jc = JAXBContext.newInstance(Train.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum15772478/input.xml");
Train train = (Train) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(train, System.out);
input.xml/Output
在下面的 XML 中,我添加了您问题的 XML 文档中缺少的必要命名空间声明。
<train:Train
xmlns:train="http://mycompany/train"
xmlns:passenger="http://mycompany/passenger">
<train:Color>Red</train:Color>
<train:Passengers>
<train:Passenger>
<passenger:TicketNumber>T101</passenger:TicketNumber>
</train:Passenger>
</train:Passengers>
</train:Train>
更多信息
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html【讨论】:
感谢超级彻底的回复。这解决了我的问题,并且像我想象的那样工作。我在每个“子类”中错误地使用了 XmlRootElement,并在该注释中声明了命名空间而不是 XmlType。 @Blaise Doughan 请建议我是否可以为两个命名空间使用相同的不带前缀的名称。以上是关于Jaxb:在同一个包中解组具有多个命名空间的 xml的主要内容,如果未能解决你的问题,请参考以下文章