使用 STAX 解析器将 XML 解组为三个不同对象的列表
Unmarshalling XML to three lists of different objects using STAX Parser
有没有一种方法可以让我使用 STAX 解析器有效地解析一个 XML 文档,其中包含多个不同 classes (POJO) 的对象列表。
我的 XML 的确切结构如下(class 名字不是真实的)
<?xml version="1.0" encoding="utf-8"?>
<root>
<notes />
<category_alpha>
<list_a>
<class_a_object></class_a_object>
<class_a_object></class_a_object>
<class_a_object></class_a_object>
<class_a_object></class_a_object>
.
.
.
</list_a>
<list_b>
<class_b_object></class_b_object>
<class_b_object></class_b_object>
<class_b_object></class_b_object>
<class_b_object></class_b_object>
.
.
.
</list_b>
</category_alpha>
<category_beta>
<class_c_object></class_c_object>
<class_c_object></class_c_object>
<class_c_object></class_c_object>
<class_c_object></class_c_object>
<class_c_object></class_c_object>
.
.
.
.
.
</category_beta>
</root>
我一直在使用 STAX 解析器,即 XStream 库,link:XStream
只要我的 XML 包含一个 class 个对象的列表,它就可以正常工作,但我不知道如何处理包含不同 XML 个对象列表的 XML =21=]es。
非常感谢任何帮助,如果我没有提供足够的信息或者我没有正确地表述问题,请告诉我。
我已经为提供的示例创建了一个解析器。
https://github.com/sbzDev/Whosebug/tree/master/question56087924
import com.thoughtworks.xstream.annotations.XStreamAlias;
import java.util.List;
@XStreamAlias("root")
public class Root {
String notes;
@XStreamAlias("category_alpha")
CategoryAlpha categoryAlpha;
@XStreamAlias("category_beta")
List<C> listC;
static class CategoryAlpha {
@XStreamAlias("list_a")
List<A> listA;
@XStreamAlias("list_b")
List<B> listB;
}
@XStreamAlias("class_a_object")
static class A {
}
@XStreamAlias("class_b_object")
static class B {
}
@XStreamAlias("class_c_object")
static class C {
}
}
解析器:
import com.thoughtworks.xstream.XStream;
public class SampleRootParser {
public Root parse(String xmlContent){
XStream xstream = new XStream();
xstream.processAnnotations(Root.class);
return (Root)xstream.fromXML(xmlContent);
}
}
也许您可以提供实际 XML 和预期结果?
您可以使用 Declarative Stream Mapping (DSM) 流解析库轻松将复杂的 XML 转换为 java class。它使用 StAX 来解析 XML.
我跳过获取 notes 标签并在 class_x_object 标签中添加一个字段以进行演示。
这里是 XML:
<?xml version="1.0" encoding="utf-8"?>
<root>
<notes />
<category_alpha>
<list_a>
<class_a_object>
<fieldA>A1</fieldA>
</class_a_object>
<class_a_object>
<fieldA>A2</fieldA>
</class_a_object>
<class_a_object>
<fieldA>A3</fieldA>
</class_a_object>
</list_a>
<list_b>
<class_b_object>
<fieldB>B1</fieldB>
</class_b_object>
<class_b_object>
<fieldB>B2</fieldB>
</class_b_object>
<class_b_object>
<fieldB>B3</fieldB>
</class_b_object>
</list_b>
</category_alpha>
<category_beta>
<class_c_object>
<fieldC>C1</fieldC>
</class_c_object>
<class_c_object>
<fieldC>C2</fieldC>
</class_c_object>
<class_c_object>
<fieldC>C3</fieldC>
</class_c_object>
</category_beta>
</root>
首先,您必须以 yaml 或 JSON 格式定义 XML 数据和 class 字段之间的映射。
以下是映射定义:
result:
type: object
path: /root
fields:
listOfA:
type: array
path: .*class_a_object # path is regex
fields:
fieldOfA:
path: fieldA
listOfB:
type: array
path: .*class_b_object
fields:
fieldOfB:
path: fieldB
listOfC:
type: array
path: .*class_c_object
fields:
fieldOfC:
path: fieldC
Java class 您要反序列化:
public class Root {
public List<A> listOfA;
public List<B> listOfB;
public List<C> listOfC;
public static class A{
public String fieldOfA;
}
public static class B{
public String fieldOfB;
}
public static class C{
public String fieldOfC;
}
}
Java 要解析的代码 XML:
DSM dsm=new DSMBuilder(new File("path/to/mapping.yaml")).setType(DSMBuilder.TYPE.XML).create(Root.class);
Root root = (Root)dsm.toObject(xmlFileContent);
// write root object as json
dsm.getObjectMapper().writerWithDefaultPrettyPrinter().writeValue(System.out, object);
这是输出:
{
"listOfA" : [ {"fieldOfA" : "A1"}, {"fieldOfA" : "A2"}, {"fieldOfA" : "A3"} ],
"listOfB" : [ {"fieldOfB" : "B1"}, {"fieldOfB" : "B2"}, "fieldOfB" : "B3"} ],
"listOfC" : [ {"fieldOfC" : "C1"}, {"fieldOfC" : "C2"}, {"fieldOfC" : "C3"} ]
}
更新:
As I understand from your comment, you want to read big XML file as a stream. and process data while you are reading the file.
DSM 允许您在阅读时处理数据 XML。
声明三个不同的函数来处理部分数据。
FunctionExecutor processA=new FunctionExecutor(){
@Override
public void execute(Params params) {
Root.A object=params.getCurrentNode().toObject(Root.A.class);
// process aClass; save to db. call service etc.
}
};
FunctionExecutor processB=new FunctionExecutor(){
@Override
public void execute(Params params) {
Root.B object=params.getCurrentNode().toObject(Root.B.class);
// process aClass; save to db. call service etc.
}
};
FunctionExecutor processC=new FunctionExecutor(){
@Override
public void execute(Params params) {
Root.C object=params.getCurrentNode().toObject(Root.C.class);
// process aClass; save to db. call service etc.
}
};
将函数注册到 DSM
DSMBuilder builder = new DSMBuilder(new File("path/to/mapping.yaml")).setType(DSMBuilder.TYPE.XML);
// register function
builder.registerFunction("processA",processA);
builder.registerFunction("processB",processB);
builder.registerFunction("processC",processC);
DSM dsm= builder.create();
Object object = dsm.toObject(xmlContent);
更改映射文件以调用已注册的函数
result:
type: object
path: /root
fields:
listOfA:
type: object
function: processA # when 'class_a_object' tag closed processA function will be executed.
path: .*class_a_object # path is regex
fields:
fieldOfA:
path: fieldA
listOfB:
type: object
path: .*class_b_object
function: processB# register function
fields:
fieldOfB:
path: fieldB
listOfC:
type: object
path: .*class_c_object
function: processC# register function
fields:
fieldOfC:
path: fieldC
您可以使用 Java Architecture for XML binding JAXB 和使用 POJO classes 的 Unmarshall,如下所述。
首先创建 POJO classes(我从您的 XML 文件中提取了几个节点并创建了 POJO。您可以对其余部分执行类似的操作)。下面是我考虑的XML
<?xml version="1.0" encoding="utf-8"?>
<root>
<category_alpha>
<list_a>
<class_a_object></class_a_object>
<class_a_object></class_a_object>
<class_a_object></class_a_object>
<class_a_object></class_a_object>
</list_a>
<list_b>
<class_b_object></class_b_object>
<class_b_object></class_b_object>
<class_b_object></class_b_object>
<class_b_object></class_b_object>
</list_b>
</category_alpha>
</root>
以下是根的 POJO classes,category_alpha、list_a、list_b、class_a_object 和 class_b_object
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "root")
@XmlAccessorType (XmlAccessType.FIELD)
public class Root {
@XmlElement(name = "category_alpha")
private List<CategoryAlpha> categoryAlphaList = null;
public List<CategoryAlpha> getCategoryAlphaList() {
return categoryAlphaList;
}
public void setCategoryAlphaList(List<CategoryAlpha> categoryAlphaList) {
this.categoryAlphaList = categoryAlphaList;
}
}
在下面 classes.class 中导入与上述 class 相似的 java 导入。
@XmlRootElement(name = "category_alpha")
@XmlAccessorType (XmlAccessType.FIELD)
public class CategoryAlpha {
@XmlElement(name = "list_a")
private List<ListAClass> list_a_collectionlist = null;
@XmlElement(name = "list_b")
private List<ListBClass> list_b_collectionlist = null;
public List<ListAClass> getList_a_collectionlist() {
return list_a_collectionlist;
}
public void setList_a_collectionlist(List<ListAClass> list_a_collectionlist) {
this.list_a_collectionlist = list_a_collectionlist;
}
public List<ListBClass> getList_b_collectionlist() {
return list_b_collectionlist;
}
public void setList_b_collectionlist(List<ListBClass> list_b_collectionlist) {
this.list_b_collectionlist = list_b_collectionlist;
}
}
@XmlRootElement(name = "list_a")
@XmlAccessorType (XmlAccessType.FIELD)
public class ListAClass {
@XmlElement(name = "class_a_object")
private List<ClassAObject> classAObjectList = null;
public List<ClassAObject> getClassAObjectList() {
return classAObjectList;
}
public void setClassAObjectList(List<ClassAObject> classAObjectList) {
this.classAObjectList = classAObjectList;
}
}
@XmlRootElement(name = "list_b")
@XmlAccessorType (XmlAccessType.FIELD)
public class ListBClass {
@XmlElement(name = "class_b_object")
private List<ClassBObject> classBObjectList = null;
public List<ClassBObject> getClassBObjectList() {
return classBObjectList;
}
public void setClassBObjectList(List<ClassBObject> classBObjectList) {
this.classBObjectList = classBObjectList;
}
}
@XmlRootElement(name = "class_a_object")
@XmlAccessorType (XmlAccessType.FIELD)
public class ClassAObject {
}
@XmlRootElement(name = "class_b_object")
@XmlAccessorType (XmlAccessType.FIELD)
public class ClassBObject {
}
这是主要内容class
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
public class UnmarshallMainClass {
public static void main(String[] args) throws JAXBException {
JAXBContext jaxbContext = JAXBContext.newInstance(Root.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
// This root object contains all the list of objects you are looking for
Root emps = (Root) jaxbUnmarshaller.unmarshal( new File("sample.xml") );
}
}
通过使用根对象和其他对象中的 getter,您可以检索根内所有对象的列表,如下所示。
List<CategoryAlpha> categoryAlphaList = emps.getCategoryAlphaList();
有没有一种方法可以让我使用 STAX 解析器有效地解析一个 XML 文档,其中包含多个不同 classes (POJO) 的对象列表。 我的 XML 的确切结构如下(class 名字不是真实的)
<?xml version="1.0" encoding="utf-8"?>
<root>
<notes />
<category_alpha>
<list_a>
<class_a_object></class_a_object>
<class_a_object></class_a_object>
<class_a_object></class_a_object>
<class_a_object></class_a_object>
.
.
.
</list_a>
<list_b>
<class_b_object></class_b_object>
<class_b_object></class_b_object>
<class_b_object></class_b_object>
<class_b_object></class_b_object>
.
.
.
</list_b>
</category_alpha>
<category_beta>
<class_c_object></class_c_object>
<class_c_object></class_c_object>
<class_c_object></class_c_object>
<class_c_object></class_c_object>
<class_c_object></class_c_object>
.
.
.
.
.
</category_beta>
</root>
我一直在使用 STAX 解析器,即 XStream 库,link:XStream
只要我的 XML 包含一个 class 个对象的列表,它就可以正常工作,但我不知道如何处理包含不同 XML 个对象列表的 XML =21=]es。
非常感谢任何帮助,如果我没有提供足够的信息或者我没有正确地表述问题,请告诉我。
我已经为提供的示例创建了一个解析器。 https://github.com/sbzDev/Whosebug/tree/master/question56087924
import com.thoughtworks.xstream.annotations.XStreamAlias;
import java.util.List;
@XStreamAlias("root")
public class Root {
String notes;
@XStreamAlias("category_alpha")
CategoryAlpha categoryAlpha;
@XStreamAlias("category_beta")
List<C> listC;
static class CategoryAlpha {
@XStreamAlias("list_a")
List<A> listA;
@XStreamAlias("list_b")
List<B> listB;
}
@XStreamAlias("class_a_object")
static class A {
}
@XStreamAlias("class_b_object")
static class B {
}
@XStreamAlias("class_c_object")
static class C {
}
}
解析器:
import com.thoughtworks.xstream.XStream;
public class SampleRootParser {
public Root parse(String xmlContent){
XStream xstream = new XStream();
xstream.processAnnotations(Root.class);
return (Root)xstream.fromXML(xmlContent);
}
}
也许您可以提供实际 XML 和预期结果?
您可以使用 Declarative Stream Mapping (DSM) 流解析库轻松将复杂的 XML 转换为 java class。它使用 StAX 来解析 XML.
我跳过获取 notes 标签并在 class_x_object 标签中添加一个字段以进行演示。
这里是 XML:
<?xml version="1.0" encoding="utf-8"?>
<root>
<notes />
<category_alpha>
<list_a>
<class_a_object>
<fieldA>A1</fieldA>
</class_a_object>
<class_a_object>
<fieldA>A2</fieldA>
</class_a_object>
<class_a_object>
<fieldA>A3</fieldA>
</class_a_object>
</list_a>
<list_b>
<class_b_object>
<fieldB>B1</fieldB>
</class_b_object>
<class_b_object>
<fieldB>B2</fieldB>
</class_b_object>
<class_b_object>
<fieldB>B3</fieldB>
</class_b_object>
</list_b>
</category_alpha>
<category_beta>
<class_c_object>
<fieldC>C1</fieldC>
</class_c_object>
<class_c_object>
<fieldC>C2</fieldC>
</class_c_object>
<class_c_object>
<fieldC>C3</fieldC>
</class_c_object>
</category_beta>
</root>
首先,您必须以 yaml 或 JSON 格式定义 XML 数据和 class 字段之间的映射。
以下是映射定义:
result:
type: object
path: /root
fields:
listOfA:
type: array
path: .*class_a_object # path is regex
fields:
fieldOfA:
path: fieldA
listOfB:
type: array
path: .*class_b_object
fields:
fieldOfB:
path: fieldB
listOfC:
type: array
path: .*class_c_object
fields:
fieldOfC:
path: fieldC
Java class 您要反序列化:
public class Root {
public List<A> listOfA;
public List<B> listOfB;
public List<C> listOfC;
public static class A{
public String fieldOfA;
}
public static class B{
public String fieldOfB;
}
public static class C{
public String fieldOfC;
}
}
Java 要解析的代码 XML:
DSM dsm=new DSMBuilder(new File("path/to/mapping.yaml")).setType(DSMBuilder.TYPE.XML).create(Root.class);
Root root = (Root)dsm.toObject(xmlFileContent);
// write root object as json
dsm.getObjectMapper().writerWithDefaultPrettyPrinter().writeValue(System.out, object);
这是输出:
{
"listOfA" : [ {"fieldOfA" : "A1"}, {"fieldOfA" : "A2"}, {"fieldOfA" : "A3"} ],
"listOfB" : [ {"fieldOfB" : "B1"}, {"fieldOfB" : "B2"}, "fieldOfB" : "B3"} ],
"listOfC" : [ {"fieldOfC" : "C1"}, {"fieldOfC" : "C2"}, {"fieldOfC" : "C3"} ]
}
更新:
As I understand from your comment, you want to read big XML file as a stream. and process data while you are reading the file.
DSM 允许您在阅读时处理数据 XML。
声明三个不同的函数来处理部分数据。
FunctionExecutor processA=new FunctionExecutor(){
@Override
public void execute(Params params) {
Root.A object=params.getCurrentNode().toObject(Root.A.class);
// process aClass; save to db. call service etc.
}
};
FunctionExecutor processB=new FunctionExecutor(){
@Override
public void execute(Params params) {
Root.B object=params.getCurrentNode().toObject(Root.B.class);
// process aClass; save to db. call service etc.
}
};
FunctionExecutor processC=new FunctionExecutor(){
@Override
public void execute(Params params) {
Root.C object=params.getCurrentNode().toObject(Root.C.class);
// process aClass; save to db. call service etc.
}
};
将函数注册到 DSM
DSMBuilder builder = new DSMBuilder(new File("path/to/mapping.yaml")).setType(DSMBuilder.TYPE.XML);
// register function
builder.registerFunction("processA",processA);
builder.registerFunction("processB",processB);
builder.registerFunction("processC",processC);
DSM dsm= builder.create();
Object object = dsm.toObject(xmlContent);
更改映射文件以调用已注册的函数
result:
type: object
path: /root
fields:
listOfA:
type: object
function: processA # when 'class_a_object' tag closed processA function will be executed.
path: .*class_a_object # path is regex
fields:
fieldOfA:
path: fieldA
listOfB:
type: object
path: .*class_b_object
function: processB# register function
fields:
fieldOfB:
path: fieldB
listOfC:
type: object
path: .*class_c_object
function: processC# register function
fields:
fieldOfC:
path: fieldC
您可以使用 Java Architecture for XML binding JAXB 和使用 POJO classes 的 Unmarshall,如下所述。
首先创建 POJO classes(我从您的 XML 文件中提取了几个节点并创建了 POJO。您可以对其余部分执行类似的操作)。下面是我考虑的XML
<?xml version="1.0" encoding="utf-8"?>
<root>
<category_alpha>
<list_a>
<class_a_object></class_a_object>
<class_a_object></class_a_object>
<class_a_object></class_a_object>
<class_a_object></class_a_object>
</list_a>
<list_b>
<class_b_object></class_b_object>
<class_b_object></class_b_object>
<class_b_object></class_b_object>
<class_b_object></class_b_object>
</list_b>
</category_alpha>
</root>
以下是根的 POJO classes,category_alpha、list_a、list_b、class_a_object 和 class_b_object
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "root")
@XmlAccessorType (XmlAccessType.FIELD)
public class Root {
@XmlElement(name = "category_alpha")
private List<CategoryAlpha> categoryAlphaList = null;
public List<CategoryAlpha> getCategoryAlphaList() {
return categoryAlphaList;
}
public void setCategoryAlphaList(List<CategoryAlpha> categoryAlphaList) {
this.categoryAlphaList = categoryAlphaList;
}
}
在下面 classes.class 中导入与上述 class 相似的 java 导入。
@XmlRootElement(name = "category_alpha")
@XmlAccessorType (XmlAccessType.FIELD)
public class CategoryAlpha {
@XmlElement(name = "list_a")
private List<ListAClass> list_a_collectionlist = null;
@XmlElement(name = "list_b")
private List<ListBClass> list_b_collectionlist = null;
public List<ListAClass> getList_a_collectionlist() {
return list_a_collectionlist;
}
public void setList_a_collectionlist(List<ListAClass> list_a_collectionlist) {
this.list_a_collectionlist = list_a_collectionlist;
}
public List<ListBClass> getList_b_collectionlist() {
return list_b_collectionlist;
}
public void setList_b_collectionlist(List<ListBClass> list_b_collectionlist) {
this.list_b_collectionlist = list_b_collectionlist;
}
}
@XmlRootElement(name = "list_a")
@XmlAccessorType (XmlAccessType.FIELD)
public class ListAClass {
@XmlElement(name = "class_a_object")
private List<ClassAObject> classAObjectList = null;
public List<ClassAObject> getClassAObjectList() {
return classAObjectList;
}
public void setClassAObjectList(List<ClassAObject> classAObjectList) {
this.classAObjectList = classAObjectList;
}
}
@XmlRootElement(name = "list_b")
@XmlAccessorType (XmlAccessType.FIELD)
public class ListBClass {
@XmlElement(name = "class_b_object")
private List<ClassBObject> classBObjectList = null;
public List<ClassBObject> getClassBObjectList() {
return classBObjectList;
}
public void setClassBObjectList(List<ClassBObject> classBObjectList) {
this.classBObjectList = classBObjectList;
}
}
@XmlRootElement(name = "class_a_object")
@XmlAccessorType (XmlAccessType.FIELD)
public class ClassAObject {
}
@XmlRootElement(name = "class_b_object")
@XmlAccessorType (XmlAccessType.FIELD)
public class ClassBObject {
}
这是主要内容class
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
public class UnmarshallMainClass {
public static void main(String[] args) throws JAXBException {
JAXBContext jaxbContext = JAXBContext.newInstance(Root.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
// This root object contains all the list of objects you are looking for
Root emps = (Root) jaxbUnmarshaller.unmarshal( new File("sample.xml") );
}
}
通过使用根对象和其他对象中的 getter,您可以检索根内所有对象的列表,如下所示。
List<CategoryAlpha> categoryAlphaList = emps.getCategoryAlphaList();