Unmarshalling with multiple namespaces

2019-07-02 10:54发布

So, lets say I have this xml with several namespaces.

<Envelope xmlns:pdi="http://www.mypage.com/schemas/pdi" xmlns:ib="http://www.mypage.com/schemas/ib" xmlns="http://www.mypage.com/schemas/envelope">
  <Product>
    <pdi:number>123456</pdi:number>
  </Product>
  <Instance>
    <ib:serial>abcdefg</ib:serial>
  </Instance>
</Envelope>

I'm trying to build a client for it. I have an Envelope POJO that's declared like this

@XmlRootElement(name ="Envelope", namespace = "http://www.mypage.com/schemas/envelope")
public class Envelope

and inside, it has these attributes

@XmlElement(name="Product", namespace = "http://www.mypage.com/schemas/pdi")
public Product getProduct(){...}

@XmlElement(name="Instance", namespace = "http://www.mypage.com/schemas/ib")
public Instance getInstance(){...}

Also, the Product POJO looks like this:

@XmlRootElement(name="Product", namespace = "http://www.mypage.com/schemas/pdi")
public class Product

and attribute

@XmlElement(name="pdi:number", namespace = "http://www.mypage.com/schemas/pdi")
public int getNumber(){...}

For some reason, I can't get the product number. I keep getting a request error. Am I handling the namespaces correctly, or am I missing something?

2条回答
地球回转人心会变
2楼-- · 2019-07-02 11:33

For this use case I would recommend leveraging the package level @XmlSchema annotation to specify the namespace qualification.

package-info (forum14651918/package-info.java)

@XmlSchema(
    namespace="http://www.mypage.com/schemas/envelope", 
    elementFormDefault=XmlNsForm.QUALIFIED,
    xmlns={
            @XmlNs(namespaceURI = "http://www.mypage.com/schemas/envelope", prefix = ""),
            @XmlNs(namespaceURI = "http://www.mypage.com/schemas/ib", prefix = "ib"),
            @XmlNs(namespaceURI = "http://www.mypage.com/schemas/pdi", prefix = "pdi")
    }
)
@XmlAccessorType(XmlAccessType.FIELD)
package forum14651918;

import javax.xml.bind.annotation.*;

Envelope (forum14651918/Envelope.java)

Since we have specified a namespace and elementFormDefault on the @XmlSchema annotation, all the elements corresponding to the Envelope class will be automatically qualified with the http://www.mypage.com/schemas/envelope namespace.

package forum14651918;

import javax.xml.bind.annotation.*;

@XmlRootElement(name="Envelope")
public class Envelope {

    @XmlElement(name="Product")
    private Product product;

    @XmlElement(name="Instance")
    private Instance instance;

}

Product (forum14651918/Product.java)

You can override the namespace for the Product class using the @XmlType annotation.

package forum14651918;

import javax.xml.bind.annotation.*;

@XmlType(namespace="http://www.mypage.com/schemas/pdi")
public class Product {

    private int number;

}

Instance (forum14651918/Instance.java)

You can override the namespace for the Instance class using the @XmlType annotation.

package forum14651918;

import javax.xml.bind.annotation.XmlType;

@XmlType(namespace="http://www.mypage.com/schemas/ib")
public class Instance {

    private String serial;

}

Demo (forum14651918/Demo.java)

Below is some code you can run to prove that everything works.

import java.io.File;
import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Envelope.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum14651918/input.xml");
        Envelope envelope = (Envelope) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(envelope, System.out);
    }

}

For More Information

查看更多
手持菜刀,她持情操
3楼-- · 2019-07-02 11:33

Try replacing name="pdi:number", namespace = "http://www.mypage.com/schemas/pdi" with name="number", namespace = "http://www.mypage.com/schemas/pdi". Prefix is not needed.

What is more looking at the XML it seems that namespace for both Product and Instance is http://www.mypage.com/schemas/envelope.

You should not need @XmlRootElement annotation for Product class. It is not a root element and is already configured on getProduct().

Full configuration that should be OK is:

@XmlRootElement(name ="Envelope", namespace = "http://www.mypage.com/schemas/envelope")
public class Envelope {


   @XmlElement(name="Product", namespace = "http://www.mypage.com/schemas/envelope")
   public Product getProduct(){...}

   @XmlElement(name="Instance", namespace = "http://www.mypage.com/schemas/envelope")
   public Instance getInstance(){...}

}
public class Product {

    @XmlElement(name="number", namespace = "http://www.mypage.com/schemas/pdi")
    public int getNumber(){...}
}

public class Instance {

    @XmlElement(name="serial", namespace = "http://www.mypage.com/schemas/ib")
    public String getSerial(){...}
}
查看更多
登录 后发表回答