java - 当 <test> 标签不应超过 1 个时,JAXB 始终返回最后一个 <test> 标签

标签 java xml jaxb

  1. 用户提供具有特定架构的 XML 文件
  2. 我的类采用 XML 文件并将其转换为模型 (DataFile.class)
  3. DataFile 模型将传递到下一个类以进行验证并插入到数据库中(这部分与我的问题无关)

XML 的结构如下:

<xml .../>
<dataFile>
    <header>
        <name>firstname</name>
        <name>surname</name>
    </header>
    <content>
        <row>
            <column>seb</column>
            <column>teb</column>
        </row>
        <row>
            <column>leb</column>
            <column>pleb</column>
        </row>
    </content>
</dataFile>

该架构相当牵强,请不要触发。

现在这是我的模型,由 4 个类组成,

DataFile.class:

@XmlRootElement
public class DataFile {

    private Header header;
    private Content content;

    public DataFile() {
        this.header = new Header();
        this.content = new Content();
    }

    public DataFile(Header header, Content content) {
        this.header = header;
        this.content = content;
    }

    @XmlElement
    public Header getHeader() {
        return header;
    }

    public void setHeader(Header header) {
        this.header = header;
    }

    @XmlElement
    public Content getContent() {
        return content;
    }

    public void setContent(Content content) {
        this.content = content;
    }

}

标题类

public class Header {

    private List<String> name;

    public Header() {
        this.name = new ArrayList<>();
    }

    public Header(List<String> name) {
        this.name = name;
    }

    public List<String> getName() {
        return name;
    }

    public void setName(List<String> name) {
        this.name = name;
    }
}

内容.类

public class Content {

    private List<Row> row;

    public Content() {
        this.row = new ArrayList<>();
    }

    public Content(List<Row> rows) {
        this.row = rows;
    }

    public List<Row> getRow() {
        return row;
    }

    public void setRow(List<Row> row) {
        this.row = row;
    }

}

行.类

public class Row {

    private List<String> column;

    public Row() {

    }

    public Row(List<String> column) {
        this.column = column;
    }

    public List<String> getColumn() {
        return column;
    }

    public void setColumn(List<String> column) {
        this.column = column;
    }

}

这是我用来将 XML 文件解码到 DataFile 模型的方法:

public DataFile JaxBValidate(File file) throws JAXBException {
    JAXBContext jaxbContext = JAXBContext.newInstance(DataFile.class);
    Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
    return (DataFile) jaxbUnmarshaller.unmarshal(file);
}

我遇到的问题是,如果我有超过 1 个标签,JAXB 将始终选择最后一个标签,如果有超过 1 个 header ,我希望它抛出异常。

我环顾四周,没有发现任何相关内容,我还查看了 DataFile 模型的注释,但没有找到任何内容来指定我只想有 1 个 header 标记。

我找到了一种使用 XPath 进行解析而不是使用 JAXB 的解决方案,但我很好奇其他人是否知道这方面的信息。

最佳答案

您需要定义设置字段数量的 XSD 文件并将其附加到 JAXB 解码器:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="dataFile" type="dataFileType"/>
    <xs:complexType name="headerType">
        <xs:sequence>
            <xs:element name="name" maxOccurs="unbounded" minOccurs="0"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="rowType">
        <xs:sequence>
            <xs:element name="column" maxOccurs="unbounded" minOccurs="0"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="contentType">
        <xs:sequence>
            <xs:element type="rowType" name="row" maxOccurs="unbounded" minOccurs="0"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="dataFileType">
        <xs:sequence>
            <xs:element type="headerType" name="header" maxOccurs="1"/>
            <xs:element type="contentType" name="content" maxOccurs="1"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>

这就是我们如何使用 schema 解码 XML:

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class JaxbApp {

    public static void main(String[] args) throws Exception {
        File xmlFile = new File("./resource/test.xml").getAbsoluteFile();
        File xsdFile = new File("./resource/test.xsd").getAbsoluteFile();

        SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        Schema schema = sf.newSchema(xsdFile);

        JAXBContext jaxbContext = JAXBContext.newInstance(DataFile.class);
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        unmarshaller.setSchema(schema);

        Object root = unmarshaller.unmarshal(xmlFile);
        System.out.println(root);
    }
}

对于以下 XML 有效负载:

<?xml version="1.0" encoding="UTF-8"?>
<dataFile>
    <header>
        <name>firstname</name>
        <name>surname</name>
    </header>
    <header>
        <name>firstname1</name>
        <name>surname1</name>
    </header>
    <content>
        <row>
            <column>seb</column>
            <column>teb</column>
        </row>
        <row>
            <column>leb</column>
            <column>pleb</column>
        </row>
    </content>
</dataFile>

抛出异常:

Exception in thread "main" javax.xml.bind.UnmarshalException
 - with linked exception:
[org.xml.sax.SAXParseException; systemId: file:./resource/test.xml; lineNumber: 7; columnNumber: 13; cvc-complex-type.2.4.a: Invalid content was found starting with element 'header'. One of '{content}' is expected.]
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.createUnmarshalException(AbstractUnmarshallerImpl.java:335)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.createUnmarshalException(UnmarshallerImpl.java:563)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:249)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:214)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:157)

另请参阅:

关于java - 当 <test> 标签不应超过 1 个时,JAXB 始终返回最后一个 <test> 标签,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55277206/

相关文章:

php - datetime 数据类型在 soap php 中不起作用

java - Jax-b 文字 xml 序列化

java - 包含其他对象集合的对象的 JAXB 解码问题

java - HTML5 input+datalist 使用 Selenium 控制项目选择

android - 可以在Android Action Bar中通过xml设置ActionViewClass的属性吗?

java - 我应该使用 Eclipse 插件(或 OSGi Bundles)作为普通的依赖管理工具吗?

java - 添加 spring-data-jpa 模式引用后,Spring 配置 xml 无效

java - jackson 与 jaxb

java - 通过数组使用 XML 创建 JSP

java - 使用 Windows 10 和命令行启动 Hadoop 2.7.1 : ERROR the system cannot find the file hadoop