从子元素开始使用JAXB解组

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从子元素开始使用JAXB解组相关的知识,希望对你有一定的参考价值。

我正在尝试使用JAXB以下列格式解组XML:

<return_data api_call="getuser">
    <users>
       <user>
          <username>test_me</username>
          <account_expiration_date>0000-00-00</account_expiration_date>        
       </user>
    </users>
</return_data>

我想从用户元素开始解组XML。但是,当我尝试使用'@XmlRootElement(name =“user”)时,我收到此错误:

Exception in thread "main" java.lang.RuntimeException: Unable to parse XML:
    at com.example.findAccount(AccountService.java:30)
    at com.example.main(AccountService.java:50)
Caused by: javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"return_data"). Expected elements are <{}user>
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:726)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:247)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:242)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportUnexpectedChildElement(Loader.java:109)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext$DefaultRootLoader.childElement(UnmarshallingContext.java:1131)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:556)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:538)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:153)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(AbstractSAXParser.java:509)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:379)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl$NSContentDriver.scanRootElementHook(XMLNSDocumentScannerImpl.java:605)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:3138)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:880)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:606)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:117)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:510)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:848)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:649)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:243)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:214)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:157)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:162)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:171)
    at com.example.findAccount(AccountService.java:26)
    ... 1 more

这是我的帐户模型类:

package com.example;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "user")
public class Account {

    private String username;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }
}

服务:

package com.example;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.Optional;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

import com.example.Account;

public class AccountService {

    public Optional<Account> findAccount(final String username) {

        try {
            URL url = new URL("https://example.com/foo/bar" + username);
            JAXBContext jaxbContext = JAXBContext.newInstance(Account.class);
            Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
            Account account = (Account) jaxbUnmarshaller.unmarshal(url);

            return Optional.ofNullable(account);
        } catch (JAXBException | MalformedURLException e) {
            throw new RuntimeException("Unable to parse XML:", e);
        }
    }

    public static void main(String[] args) {
        // test it //
        new AccountService().findAccount("user");
    }

}
答案

JAXB unmarshalls完整的XML,@XmlRootElement(name = "user")不会过滤“你在XML中看到的第一个user元素”。

如果你想要这个(“你在XML中看到的第一个user元素”),有几个选项。

  • 最简单的可能是解组完整的XML,然后从结果结构中检索user对象。
  • 另一种选择是使用StAX。有关如何执行此操作,请参阅this article by Blaise Doughan
  • 您也可以预先过滤使用SAX解析的XML,但这可能并不那么容易。
  • 最后,您可以先将XML解析为DOM,找到所需的user节点并解组此节点。

如果你在user元素周围没有太多的XML,我只需要解析完整的XML。否则我会选择StAX选项。这将是一些事情:

    XMLInputFactory xif = XMLInputFactory.newFactory();
    StreamSource xml = new StreamSource("https://example.com/foo/bar" + username);
    XMLStreamReader xsr = xif.createXMLStreamReader(xml);
    xsr.nextTag();
    while(!xsr.getLocalName().equals("user")) {
        xsr.nextTag();
    }

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

    Account user = jb.getValue();

(从this article复制粘贴,经过一些调整,根本没有经过测试。)

感谢Blaise Doughan

以上是关于从子元素开始使用JAXB解组的主要内容,如果未能解决你的问题,请参考以下文章

解组非根元素时的 JAXB 模式验证

使用命名空间和前缀的 JAXB 解组

Jaxb2Marshaller在春天解组 - 意想不到的元素

如何跳过字段并仅使用JAXB解组该字段的特定成员?

如何调试 JAXB 解组?

JAXB使用XMLReader解组时的未读属性