如何使用单个元素和值解组简单的XML

时间:2013-11-06 08:40:51

标签: xml spring unmarshalling resttemplate

我尝试使用Spring的RestTemplate和JAXB解组从外部Web服务收到的以下非常简单的XML:

<?xml version="1.0" encoding="utf-8"?>
<double xmlns="http://www.example.com/">0.061</double>

这是我用来解组XML的类。我已经尝试了@XmlRootElement,@ XMLElement和@XmlValue的各种组合,但无法让它工作。

@XmlRootElement
public class ExchangeRateWebServiceResponse {

    private double rate;

    @XmlElement(name = "double")
    public double getRate() {
        return rate;
    }

    public void setRate(double rate) {
        this.rate = rate;
    }    
}

使用RestTemplate执行Web服务调用的方法:

public double getExchangeRate(String fromCurrency, String toCurrency, 
                              String exchangeRateURL) {
    RestTemplate restTemplate = new RestTemplate();

    ExchangeRateWebServiceResponse result = 
        restTemplate.getForObject(exchangeRateURL,
            ExchangeRateWebServiceResponse.class, 
                fromCurrency, toCurrency);

    return result.getRate();
}

这是我得到的例外:

org.springframework.http.converter.HttpMessageNotReadableException: Could not unmarshal to [class za.co.example.server.finance.ExchangeRateWebServiceResponse]: unexpected element (uri:"http://www.example.com/", local:"double"). Expected elements are <{}exchangeRateWebServiceResponse>; nested exception is javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.example.com/", local:"double"). Expected elements are <{}exchangeRateWebServiceResponse>
at org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter.readFromSource(Jaxb2RootElementHttpMessageConverter.java:82)
at org.springframework.http.converter.xml.AbstractXmlHttpMessageConverter.readInternal(AbstractXmlHttpMessageConverter.java:61)
at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:153)
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:103)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:496)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:452)
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:222)
at za.co.example.server.finance.ExchangeRateWebService.getExchangeRate(ExchangeRateWebService.java:21)
at za.co.example.test.suites.integration.component.external.ExchangeRateWebserviceTests.testGetZARToGBPRate_shouldReturnAnExchangeRate(ExchangeRateWebserviceTests.java:18)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:77)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:195)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:63)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.example.com/", local:"double"). Expected elements are <{}exchangeRateWebServiceResponse>
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:647)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:243)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:238)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportUnexpectedChildElement(Loader.java:105)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext$DefaultRootLoader.childElement(UnmarshallingContext.java:1048)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:483)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:465)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:135)
at org.apache.xerces.parsers.AbstractSAXParser.startElement(Unknown Source)
at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
at org.apache.xerces.impl.XMLNSDocumentScannerImpl$NSContentDispatcher.scanRootElementHook(Unknown Source)
at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:203)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:175)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:157)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:125)
at org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter.readFromSource(Jaxb2RootElementHttpMessageConverter.java:74)
... 34 more

2 个答案:

答案 0 :(得分:3)

你需要在你的java对象上有命名空间。

@XmlElement(name = "double", namespace = "http://www.example.com/" )

修改

您可以在单独的package-info类中配置命名空间,并将其放在java类包

@XmlSchema(
xmlns = { namespace = "http://www.example.com/",
elementFormDefault = XmlNsForm.QUALIFIED) 

这样您就可以只在根级别定义名称空间,不需要在每个xml元素上定义,也可以配置多个名称空间。

此链接将提供有关package-info.java

的更多详细信息

http://java.dzone.com/articles/jaxb-and-root-elements

答案 1 :(得分:0)

在@pappu_kutty的帮助下,我得出结论我需要在@XmlRootElement中指定命名空间和元素名称,然后将@XmlValue添加到getRate()或setRate()以获取根元素的值。

@XmlRootElement(name = "double", namespace = "http://www.example.com/")
public class ExchangeRateWebServiceResponse {

    private double rate;

    @XmlValue
    public double getRate() {
        return rate;
    }

    public void setRate(double rate) {
        this.rate = rate;
    }

}