[英]Unmarshalling complex nested list of xml items using JAXB
I am trying to unmarshall this complex xml, but not able to do it successfully.我正在尝试解组这个复杂的 xml,但无法成功。 Below is my xml:下面是我的 xml:
<ImportSession xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Batches>
<Batch BatchClassName="BC">
<BatchFields>
<BatchField Name="N11" Value="N21"/>
<BatchField Name="N12" Value="N22"/>
<BatchField Name="N13" Value="N23"/>
<BatchField Name="N14" Value="N24"/>
<BatchField Name="N15" Value="N25"/>
</BatchFields>
<Documents>
<Document FormTypeName="F1">
<IndexFields>
<IndexField Name="NM11" Value="V11"/>
<IndexField Name="NM12" Value="V12"/>
<IndexField Name="NM13" Value="V13"/>
<IndexField Name="NM14" Value="V14"/>
</IndexFields>
<Pages>
<Page ImportFileName="P1.pdf"/>
</Pages>
</Document>
<Document FormTypeName="F2">
<IndexFields>
<IndexField Name="NM21" Value="V21"/>
<IndexField Name="NM22" Value="V22"/>
<IndexField Name="NM23" Value="V23"/>
<IndexField Name="NM24" Value="V24"/>
</IndexFields>
<Pages>
<Page ImportFileName="P2.pdf"/>
</Pages>
</Document>
<Document FormTypeName="F3">
<IndexFields>
<IndexField Name="NM31" Value="V31"/>
<IndexField Name="NM32" Value="V32"/>
<IndexField Name="NM33" Value="V33"/>
<IndexField Name="NM34" Value="V34"/>
</IndexFields>
<Pages>
<Page ImportFileName="P3.pdf"/>
</Pages>
</Document>
</Documents>
</Batch>
</Batches>
</ImportSession>
This is my ImportSession.java这是我的 ImportSession.java
import java.io.Serializable;
import java.util.List;
import javax.xml.bind.annotation.*;
import lombok.Getter;
import lombok.Setter;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.ToString;
@XmlRootElement(name = "ImportSession")
@XmlAccessorType(XmlAccessType.FIELD)
@ToString
public class ImportSession {
@XmlElement(name = "Batches")
private Batches batches;
@XmlAccessorType(XmlAccessType.FIELD)
@ToString
public static class Batches implements Serializable {
@XmlElement(name = "Batch")
private Batch batch;
@XmlAccessorType(XmlAccessType.FIELD)
@ToString
public static class Batch implements Serializable {
@XmlElement(name = "Documents")
private Documents documents;
@XmlAccessorType(XmlAccessType.FIELD)
@ToString
public static class Documents implements Serializable {
@XmlElement(name = "Document")
private Document document;
@XmlAccessorType(XmlAccessType.FIELD)
@ToString
public static class Document implements Serializable {
@XmlElement(name = "IndexFields")
private IndexFields indexFields;
@XmlElement(name = "Pages")
private Pages pages;
@XmlAccessorType(XmlAccessType.FIELD)
@ToString
public static class IndexFields implements Serializable {
@XmlElement(name = "IndexField")
private List<IndexField> indexField;
@XmlAccessorType(XmlAccessType.FIELD)
@ToString
public static class IndexField implements Serializable {
@XmlAttribute(name = "Name")
private String name;
@XmlAttribute(name = "Value")
private String value;
}
}
@XmlAccessorType(XmlAccessType.FIELD)
@ToString
public static class Pages implements Serializable {
@XmlElement(name = "Page")
private List<Page> page;
@XmlAccessorType(XmlAccessType.FIELD)
@ToString
public static class Page implements Serializable {
@XmlAttribute(name = "ImportFileName")
private String importFileName;
}
}
}
}
}
}
}
Below is my unmarshalling code:下面是我的解组代码:
private static void main(String xmlFile) {
try {
JAXBContext jaxbContext = JAXBContext.newInstance(ImportSession.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
ImportSession ImportSession = (ImportSession) unmarshaller.unmarshal(new File(xmlFile));
System.out.println("output = " + ImportSession);
} catch (Exception e) {
System.err.println(e.getMessage());
e.printStackTrace();
}
}
In my Documents class, if I have在我的文档 class 中,如果我有
private Document document;
It works fine, but then it only gives me last document of my xml.它工作正常,但它只给了我 xml 的最后一个文档。 But if I try to put:但是,如果我尝试说:
private List<Document> document;
Code just comes out with nothing, no errors as well.代码一无所有,也没有错误。 Need help in analyzing what I am missing.在分析我所缺少的内容时需要帮助。
I don't want BatchFields/BatchField in my output, so I don't have that same in my class schema.我不想在我的 output 中使用 BatchFields/BatchField,所以在我的 class 架构中没有相同的内容。
I have generated the java class ImportSession.java
with xjc
and got different result.我已经用xjc
生成了 java class ImportSession.java
并得到了不同的结果。
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"batches"
})
@XmlRootElement(name = "ImportSession")
public class ImportSession {
@XmlElement(name = "Batches", required = true)
protected ImportSession.Batches batches;
public ImportSession.Batches getBatches() {
return batches;
}
public void setBatches(ImportSession.Batches value) {
this.batches = value;
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"batch"
})
public static class Batches {
@XmlElement(name = "Batch", required = true)
protected ImportSession.Batches.Batch batch;
public ImportSession.Batches.Batch getBatch() {
return batch;
}
public void setBatch(ImportSession.Batches.Batch value) {
this.batch = value;
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"batchFields",
"documents"
})
public static class Batch {
@XmlElement(name = "BatchFields", required = true)
protected ImportSession.Batches.Batch.BatchFields batchFields;
@XmlElement(name = "Documents", required = true)
protected ImportSession.Batches.Batch.Documents documents;
@XmlAttribute(name = "BatchClassName", required = true)
protected String batchClassName;
public ImportSession.Batches.Batch.BatchFields getBatchFields() {
return batchFields;
}
public void setBatchFields(ImportSession.Batches.Batch.BatchFields value) {
this.batchFields = value;
}
public ImportSession.Batches.Batch.Documents getDocuments() {
return documents;
}
public void setDocuments(ImportSession.Batches.Batch.Documents value) {
this.documents = value;
}
public String getBatchClassName() {
return batchClassName;
}
public void setBatchClassName(String value) {
this.batchClassName = value;
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"batchField"
})
public static class BatchFields {
@XmlElement(name = "BatchField", required = true)
protected List<ImportSession.Batches.Batch.BatchFields.BatchField> batchField;
public List<ImportSession.Batches.Batch.BatchFields.BatchField> getBatchField() {
if (batchField == null) {
batchField = new ArrayList<ImportSession.Batches.Batch.BatchFields.BatchField>();
}
return this.batchField;
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "")
public static class BatchField {
@XmlAttribute(name = "Name", required = true)
protected String name;
@XmlAttribute(name = "Value", required = true)
protected String value;
public String getName() {
return name;
}
public void setName(String value) {
this.name = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"document"
})
public static class Documents {
@XmlElement(name = "Document", required = true)
protected List<ImportSession.Batches.Batch.Documents.Document> document;
public List<ImportSession.Batches.Batch.Documents.Document> getDocument() {
if (document == null) {
document = new ArrayList<ImportSession.Batches.Batch.Documents.Document>();
}
return this.document;
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"indexFields",
"pages"
})
public static class Document {
@XmlElement(name = "IndexFields", required = true)
protected ImportSession.Batches.Batch.Documents.Document.IndexFields indexFields;
@XmlElement(name = "Pages", required = true)
protected ImportSession.Batches.Batch.Documents.Document.Pages pages;
@XmlAttribute(name = "FormTypeName", required = true)
protected String formTypeName;
public ImportSession.Batches.Batch.Documents.Document.IndexFields getIndexFields() {
return indexFields;
}
public void setIndexFields(ImportSession.Batches.Batch.Documents.Document.IndexFields value) {
this.indexFields = value;
}
public ImportSession.Batches.Batch.Documents.Document.Pages getPages() {
return pages;
}
public void setPages(ImportSession.Batches.Batch.Documents.Document.Pages value) {
this.pages = value;
}
public String getFormTypeName() {
return formTypeName;
}
public void setFormTypeName(String value) {
this.formTypeName = value;
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"indexField"
})
public static class IndexFields {
@XmlElement(name = "IndexField", required = true)
protected List<ImportSession.Batches.Batch.Documents.Document.IndexFields.IndexField> indexField;
public List<ImportSession.Batches.Batch.Documents.Document.IndexFields.IndexField> getIndexField() {
if (indexField == null) {
indexField = new ArrayList<ImportSession.Batches.Batch.Documents.Document.IndexFields.IndexField>();
}
return this.indexField;
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "")
public static class IndexField {
@XmlAttribute(name = "Name", required = true)
protected String name;
@XmlAttribute(name = "Value", required = true)
protected String value;
public String getName() {
return name;
}
public void setName(String value) {
this.name = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"page"
})
public static class Pages {
@XmlElement(name = "Page", required = true)
protected ImportSession.Batches.Batch.Documents.Document.Pages.Page page;
public ImportSession.Batches.Batch.Documents.Document.Pages.Page getPage() {
return page;
}
public void setPage(ImportSession.Batches.Batch.Documents.Document.Pages.Page value) {
this.page = value;
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "")
public static class Page {
@XmlAttribute(name = "ImportFileName", required = true)
protected String importFileName;
public String getImportFileName() {
return importFileName;
}
public void setImportFileName(String value) {
this.importFileName = value;
}
}
}
}
}
}
}
}
I have first generated the xsd
file from your xml
file with this online site:https://www.liquid-technologies.com/online-xml-to-xsd-converter我首先使用此在线站点从您的xml
文件生成xsd
文件:https://www.xmlto-technologiesd-converterline
Generated xsd
(I name it "test.xsd"):生成xsd
(我将其命名为“test.xsd”):
<?xml version="1.0" encoding="utf-8"?>
<!-- Created with Liquid Technologies Online Tools 1.0 (https://www.liquid-technologies.com) -->
<xs:schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="ImportSession">
<xs:complexType>
<xs:sequence>
<xs:element name="Batches">
<xs:complexType>
<xs:sequence>
<xs:element name="Batch">
<xs:complexType>
<xs:sequence>
<xs:element name="BatchFields">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="BatchField">
<xs:complexType>
<xs:attribute name="Name" type="xs:string" use="required" />
<xs:attribute name="Value" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Documents">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="Document">
<xs:complexType>
<xs:sequence>
<xs:element name="IndexFields">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="IndexField">
<xs:complexType>
<xs:attribute name="Name" type="xs:string" use="required" />
<xs:attribute name="Value" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Pages">
<xs:complexType>
<xs:sequence>
<xs:element name="Page">
<xs:complexType>
<xs:attribute name="ImportFileName" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="FormTypeName" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="BatchClassName" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Generation of ImportSession.java
( xjc
is included in JDK8): ImportSession.java
(JDK8中包含xjc
)的生成:
$ xjc test.xsd
analyse dun schéma...
compilation dun schéma...
generated/ImportSession.java
generated/ObjectFactory.java
I have remove the first line package generated;
我已经删除了package generated;
and many many auto-generated comments.以及许多自动生成的评论。
Now,现在,
System.out.println("output = " + ImportSession.getBatches().getBatch().getDocuments().getDocument().size());
show 3
.显示3
。
Your <Documents>
XML element contains several <Document>
elements.您的<Documents>
XML 元素包含多个<Document>
元素。
Therefore in your Documents
Java class you don't need a member of type Document
, but instead of type List<Document>
.因此,在您的Documents
Java class 中,您不需要Document
类型的成员,而是List<Document>
类型的成员。 So in your Documents
class you need to replace所以在你的Documents
class 你需要更换
@XmlElement(name = "Document")
private Document document;
by经过
@XmlElement(name = "Document")
private List<Document> documents;
I also changed the member name from document
to documents
, because using a plural word is common practice for lists.我还将成员名称从document
更改为documents
,因为使用复数词是列表的常见做法。
While the above modification already fixes your problem, there is even more room for improvement:虽然上面的修改已经解决了你的问题,但还有更多的改进空间:
Currently you have two separate classes Documents
and Document
for modeling XML content like:目前,您有两个单独的类Documents
和Document
用于建模 XML 内容,例如:
<Documents>
<Document ...>...</Document>
<Document ...>...</Document>
<Document ...>...</Document>
</Documents>
You can simplify the Java code by using the @XmlElementWrapper
annotation.您可以使用@XmlElementWrapper
注释来简化 Java 代码。 In your Batch
class you can replace在您的Batch
class 中,您可以替换
@XmlElement(name = "Documents")
private Documents documents;
by经过
@XmlElementWrapper(name = "Documents")
@XmlElement(name = "Document")
private List<Document> documents;
By doing so you don't need the Documents
class anymore.通过这样做,您不再需要Documents
class。
You might want to do similar modifications for the other lists in your Java code corresponding to您可能希望对 Java 代码中对应的其他列表进行类似的修改
<Batches>
containing several <Batch>
elements <Batches>
包含多个<Batch>
元素<BatchFields>
containing several <BatchField>
elements <BatchFields>
包含多个<BatchField>
元素<IndexFields>
containing several <IndexField>
elements <IndexFields>
包含多个<IndexField>
元素<Pages>
containing several <Page>
elements <Pages>
包含多个<Page>
元素
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.