Jaxb:在同一个包中解组带有多个名称空间的xml

我是新手在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 

火车包含一个乘客名单,所以有一个属性

 private Set 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:

  Red   T101    

现在我解组我收到的这个xml并设置了Train的Color属性并设置了Passenger的TicketNumber属性。 但是我不知道为什么我需要在TicketNumber上的XmlElement注释上添加名称空间url才能使用它,但我不需要为Train上的Color属性执行此操作。 如果我从TicketNumber上的XmlElement注释中删除namespace属性,则xml中的值不会映射到该对象,除非我还从xml请求中删除了名称空间前缀。 我觉得因为我已经在XmlRootElement for Passenger上定义了namespace属性,所以我不应该为类中的每个字段都这样做,就像我没有为Train一样,所以我假设我必须设置错误。 有人能指出我正确的方向吗? 谢谢!

下面解释了命名空间如何在JAXB(JSR-222)中基于您的模型工作。

JAVA模型

包信息

以下是@XmlSchema注释的修改版本。 它包含一些关键信息:

  • namespace – 将用于限定全局元素的默认命名空间(对应于未指定其他命名空间的@XmlRootElement@XmlElementDecl注释(以及基于elementFormDefault值的本地元素)。
  • elementFormDefault默认情况下只有全局元素是名称空间限定的,但是通过将值设置为XmlNsForm.QUALIFIED所有没有指定显式名称空间的元素都将使用namespace值进行限定。
  • xmlns是JAXB impl应该用于这些命名空间的首选前缀集(尽管它们可能使用其他前缀)。
 @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 passengers; @XmlElementWrapper(name="Passengers") @XmlElement(name="Passenger") public List getPassengers() { return passengers; } public void setPassengers(List 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; } } 

演示代码

可以运行以下演示代码来certificate一切正常:

演示

 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中/输出

在下面的XML中,我添加了问题中XML文档中缺少的必要命名空间声明。

  Red   T101    

欲获得更多信息