JAXB unmarshall с пространствами имен и префиксом

Я использую JAXB для синтаксического анализа элементов XML из ответа SOAP. Я определил классы POJO для элементов xml. Я тестировал классы pojo без пространства имен и префикс его рабочего штрафа. Однако, когда я пытаюсь проанализировать пространства имен и префикс, обращенные к следующему исключению. Требование состоит в анализе ввода из объекта SOAPMessage

javax.xml.bind.UnmarshalException: unexpected element (uri:"http://schemas.xmlsoap.org/soap/envelope/", local:"Envelope"). Expected elements are <{}Envelope>

Попробовал исправить, создав @XMLSchema для пакета в package-info.java и разместив этот файл в папке пакета. Может ли кто-нибудь из вас направлять меня для продвижения вперед?

Написал это сообщение, но не помог мне.

EDITED: XMLSchema

@javax.xml.bind.annotation.XmlSchema (
    xmlns = {  @javax.xml.bind.annotation.XmlNs(prefix = "env", 
                 namespaceURI="http://schemas.xmlsoap.org/soap/envelope/"),
      @javax.xml.bind.annotation.XmlNs(prefix="ns3", namespaceURI="http://www.xxxx.com/ncp/oomr/dto/")
    }
  )
package com.one.two;

Заранее спасибо

Ответ 1

Это можно сделать без изменения сгенерированного кода JAXB с использованием стандартного класса SOAPMessage. Я написал об этом здесь и здесь

Немного неудобно, но работает правильно.

Ранжирование

Farm farm = new Farm();
farm.getHorse().add(new Horse());
farm.getHorse().get(0).setName("glue factory");
farm.getHorse().get(0).setHeight(BigInteger.valueOf(123));

Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
Marshaller marshaller = JAXBContext.newInstance(Farm.class).createMarshaller();
marshaller.marshal(farm, document);
SOAPMessage soapMessage = MessageFactory.newInstance().createMessage();
soapMessage.getSOAPBody().addDocument(document);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
soapMessage.writeTo(outputStream);
String output = new String(outputStream.toByteArray());

Демаршаллизация

String example =
        "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"><soapenv:Header /><soapenv:Body><ns2:farm xmlns:ns2=\"http://adamish.com/example/farm\"><horse height=\"123\" name=\"glue factory\"/></ns2:farm></soapenv:Body></soapenv:Envelope>";
SOAPMessage message = MessageFactory.newInstance().createMessage(null,
        new ByteArrayInputStream(example.getBytes()));
Unmarshaller unmarshaller = JAXBContext.newInstance(Farm.class).createUnmarshaller();
Farm farm = (Farm)unmarshaller.unmarshal(message.getSOAPBody().extractContentAsDocument());

Ответ 2

Вот как вы можете обрабатывать свое использование cae:

Если вам нужно отобразить элемент Envelope

пакет-инфо

Обычно вы используете @XmlSchema следующим образом. Использование свойств namespace и elementFormDefault, как я сделал, означает, что все данные, сопоставленные с элементами XML, если иначе отображаемое не будет принадлежать пространству имен http://www.xxxx.com/ncp/oomr/dto/. Информация, указанная в xmlns, предназначена для генерации XML-схемы, хотя некоторые реализации JAXB используют это, чтобы определить предпочтительный префикс для пространства имен при сортировке (см. http://blog.bdoughan.com/2011/11/jaxb-and-namespace-prefixes.html).

@XmlSchema (
    namespace="http://www.xxxx.com/ncp/oomr/dto/",
    elementFormDefault=XmlNsForm.QUALIFIED,
    xmlns = {  
        @XmlNs(prefix = "env", namespaceURI="http://schemas.xmlsoap.org/soap/envelope/"),
        @XmlNs(prefix="whatever", namespaceURI="http://www.xxxx.com/ncp/oomr/dto/")
    }
  )
package com.one.two;

import javax.xml.bind.annotation.*;

Конверт

Если в com.one.two вам нужно сопоставить элементы из пространства имен, отличного от http://www.xxxx.com/ncp/oomr/dto/, то вам нужно указать его в аннотациях @XmlRootElement и @XmlElement.

package com.one.two;

import javax.xml.bind.annotation.*;

@XmlRootElement(name="Envelope", namespace="http://schemas.xmlsoap.org/soap/envelope/")
@XmlAccessorType(XmlAccessType.FIELD)
public class Envelope {

    @XmlElement(name="Body", namespace="http://schemas.xmlsoap.org/soap/envelope/")
    private Body body;

}

Дополнительная информация

Если вы просто хотите отобразить тело

Вы можете использовать синтаксический анализатор StAX для синтаксического анализа сообщения и перехода к части полезной нагрузки и отменить его:

import javax.xml.bind.*;
import javax.xml.stream.*;
import javax.xml.transform.stream.StreamSource;

public class UnmarshalDemo {

    public static void main(String[] args) throws Exception {
        XMLInputFactory xif = XMLInputFactory.newFactory();
        StreamSource xml = new StreamSource("src/blog/stax/middle/input.xml");
        XMLStreamReader xsr = xif.createXMLStreamReader(xml);
        xsr.nextTag();
        while(!xsr.getLocalName().equals("return")) {
            xsr.nextTag();
        }

        JAXBContext jc = JAXBContext.newInstance(Customer.class);
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        JAXBElement<Customer> jb = unmarshaller.unmarshal(xsr, Customer.class);
        xsr.close();
    }

}

Дополнительная информация

Ответ 3

Просто хотел добавить к существующим ответам - в то время как unmarshalling, если XML-документ не является пространством имен, вы можете получить сообщение об ошибке: javax.xml.bind.UnmarshalException: неожиданный элемент (uri: " http://some.url"; local: "someOperation" )

Если это так, вы можете просто использовать другой метод для unmarshaller:

Unmarshaller unmarshaller = JAXBContext.newInstance(YourObject.class).createUnmarshaller();
JAXBElement<YourObject> element = unmarshaller.unmarshal(message.getSOAPBody().extractContentAsDocument(), YourObject.class);
YourObject yo = element.getValue();