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

时间:2013-04-02 19:17:18

标签: java xml namespaces jaxb annotations

我是新手在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<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注释中删除namespace属性,则xml中的值将不会映射到该对象,除非我还从xml请求中删除了名称空间前缀。我觉得因为我已经在XmlRootElement for Passenger上定义了namespace属性,所以我不应该为类中的每个字段都这样做,就像我没有为Train一样,所以我假设我必须设置错误。有人能指出我正确的方向吗?谢谢!

1 个答案:

答案 0 :(得分:27)

以下是基于您的模型在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类对应的所有元素都对应于namespace注释中指定的@XmlSchema,因此我们不需要指定任何命名空间信息。

  • 全局元素 - @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注释覆盖namespace @XmlSchema注释。

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;
    }

}

DEMO CODE

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

<强>演示

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文档中缺少的必要命名空间声明。

<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>

更多信息