当不应超过1个<test>标记时,JAXB总是返回最后一个<test>标记

时间:2019-03-21 09:26:49

标签: 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;
    }

}

Header.class

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;
    }
}

Content.class

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;
    }

}

Row.class

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个,我希望它在这里抛出异常。

我环顾四周,没有发现任何问题,也没有查看DataFile模型的注释,也没有发现任何东西指定我只想拥有1个标头标记。

我找到了一种使用XPath进行解析而不是使用JAXB的解决方案,但是我很好奇是否有人对此有所了解。

2 个答案:

答案 0 :(得分:1)

您需要定义设置了字段数的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>

这是我们可以使用架构解集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)

另请参阅:

答案 1 :(得分:0)

尝试一下,

DataFile.java

@XmlRootElement
public class DataFile {

    private List<Header> header;
    private List<Content> content;

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

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

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

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

Header.java

@XmlRootElement
public class Header {

    private List<String> name;

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

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

Content.java

@XmlRootElement
public class Content {

    private List<Row> row;

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

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

Row.java

@XmlRootElement
public class Row {

    private List<String> column;

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

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

用于DataFile解组

File file = new File("xmlFile.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(DataFile.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
DataFile dataFile = (DataFile) jaxbUnmarshaller.unmarshal(file);

用于获取给定xml文件中<header>个标签的数量

int noOfHeader = dataFile.getHeader().size();