如何使用 Jackson 解析 XML 流式传输文件 API
How to use Jackson to parse XML files with streaming API
我正在寻找一种使用 kotlin 解析大型 xml 的方法。
我常用的JSON解析器是Jackson,我知道它也可以用来解析xml。
源文件太大,无法使用 DOM 方法进行解析,我必须改为使用流 API。我可以找到几个关于如何使用 jackson streaming API 和 JSON 的示例,但没有关于 XML 的内容。
文档 https://github.com/FasterXML/jackson-dataformat-xml 说
Although module implements low-level (JsonFactory / JsonParser / JsonGenerator) abstractions, most usage is through data-binding level. This because a small number of work-arounds have been added at data-binding level, to work around XML peculiarities:
这让我担心如果使用此库的 XML 流媒体方法甚至可能 and/or 支持。
读取树结构需要进程启动(例如 <element>
用于 XML 或 { / [
用于 JSON) 这种方式不可能在以流方式处理时读取整个对象。
让根包装器和一大堆汽车(为简洁起见,我使用 lombok 注释):
@Getter
@Setter
@JacksonXmlRootElement
@NoArgsConstructor
@AllArgsConstructor
static class CarBook {
@JacksonXmlProperty(isAttribute = true)
private int version;
@JacksonXmlElementWrapper(localName = "cars")
@JacksonXmlProperty(localName = "car")
private List<Car> cars;
}
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
static class Car {
private String model;
private String plate;
}
然后,在所有列表(可能是其他成员)被完全读取之前,您无法获得 CarBook
对象。
通常的方法是使用 XMLStreamReader
并逐个检查令牌,但您可以使用 jackson 使用 XmlMapper
方法解析整个对象:
/**
* Method for reading a single XML value from given XML-specific input
* source; useful for incremental data-binding, combining traversal using
* basic Stax {@link XMLStreamReader} with data-binding by Jackson.
*
* @since 2.4
*/
public <T> T readValue(XMLStreamReader r, Class<T> valueType) throws IOException {
return readValue(r, _typeFactory.constructType(valueType));
}
以大(1,2G)文件为例:
<CarBook version="1"><cars>
<car><model>Alfa Romeo Spider</model><plate>27437</plate></car>
<car><model>Almera</model><plate>6429</plate></car>
<car><model>Audi 80 and 90</model><plate>4898</plate></car>
<car><model>Audi A3</model><plate>21259</plate></car>
<car><model>Audi A4</model><plate>21056</plate></car>
<car><model>Audi Coupé</model><plate>5623</plate></car>
<car><model>Austin Metro</model><plate>26446</plate></car>
<car><model>BMW 3 Series</model><plate>16338</plate></car>
<car><model>BMW 5 Series</model><plate>29859</plate></car>
...
那个,你可以偷偷看
public static void main(String... args) throws IOException, XMLStreamException {
XmlMapper xm = new XmlMapper();
XMLInputFactory xif = XMLInputFactory.newInstance();
XMLStreamReader xr = xif.createXMLStreamReader(new FileInputStream(/* 1,2G file */ "/home/josejuan/tmp/all.cars.xml"));
// you must to read step by step
while (xr.hasNext()) {
xr.next();
if (xr.getEventType() == START_ELEMENT) {
System.out.println(xr.getLocalName());
if ("car".equals(xr.getLocalName())) {
Car car = xm.readValue(xr, Car.class);
System.out.println(car);
if ("21056".equals(car.getPlate()))
break;
}
}
}
System.out.println("== End Of Process ==");
}
有输出
CarBook
cars
car
WithLazyJackson.Car(model=Alfa Romeo Spider, plate=27437)
car
WithLazyJackson.Car(model=Almera, plate=6429)
car
WithLazyJackson.Car(model=Audi 80 and 90, plate=4898)
car
WithLazyJackson.Car(model=Audi A3, plate=21259)
car
WithLazyJackson.Car(model=Audi A4, plate=21056)
== End Of Process ==
在 19.800.000 辆中只读取了 5 辆汽车
我正在寻找一种使用 kotlin 解析大型 xml 的方法。
我常用的JSON解析器是Jackson,我知道它也可以用来解析xml。
源文件太大,无法使用 DOM 方法进行解析,我必须改为使用流 API。我可以找到几个关于如何使用 jackson streaming API 和 JSON 的示例,但没有关于 XML 的内容。 文档 https://github.com/FasterXML/jackson-dataformat-xml 说
Although module implements low-level (JsonFactory / JsonParser / JsonGenerator) abstractions, most usage is through data-binding level. This because a small number of work-arounds have been added at data-binding level, to work around XML peculiarities:
这让我担心如果使用此库的 XML 流媒体方法甚至可能 and/or 支持。
读取树结构需要进程启动(例如 <element>
用于 XML 或 { / [
用于 JSON) 这种方式不可能在以流方式处理时读取整个对象。
让根包装器和一大堆汽车(为简洁起见,我使用 lombok 注释):
@Getter
@Setter
@JacksonXmlRootElement
@NoArgsConstructor
@AllArgsConstructor
static class CarBook {
@JacksonXmlProperty(isAttribute = true)
private int version;
@JacksonXmlElementWrapper(localName = "cars")
@JacksonXmlProperty(localName = "car")
private List<Car> cars;
}
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
static class Car {
private String model;
private String plate;
}
然后,在所有列表(可能是其他成员)被完全读取之前,您无法获得 CarBook
对象。
通常的方法是使用 XMLStreamReader
并逐个检查令牌,但您可以使用 jackson 使用 XmlMapper
方法解析整个对象:
/**
* Method for reading a single XML value from given XML-specific input
* source; useful for incremental data-binding, combining traversal using
* basic Stax {@link XMLStreamReader} with data-binding by Jackson.
*
* @since 2.4
*/
public <T> T readValue(XMLStreamReader r, Class<T> valueType) throws IOException {
return readValue(r, _typeFactory.constructType(valueType));
}
以大(1,2G)文件为例:
<CarBook version="1"><cars>
<car><model>Alfa Romeo Spider</model><plate>27437</plate></car>
<car><model>Almera</model><plate>6429</plate></car>
<car><model>Audi 80 and 90</model><plate>4898</plate></car>
<car><model>Audi A3</model><plate>21259</plate></car>
<car><model>Audi A4</model><plate>21056</plate></car>
<car><model>Audi Coupé</model><plate>5623</plate></car>
<car><model>Austin Metro</model><plate>26446</plate></car>
<car><model>BMW 3 Series</model><plate>16338</plate></car>
<car><model>BMW 5 Series</model><plate>29859</plate></car>
...
那个,你可以偷偷看
public static void main(String... args) throws IOException, XMLStreamException {
XmlMapper xm = new XmlMapper();
XMLInputFactory xif = XMLInputFactory.newInstance();
XMLStreamReader xr = xif.createXMLStreamReader(new FileInputStream(/* 1,2G file */ "/home/josejuan/tmp/all.cars.xml"));
// you must to read step by step
while (xr.hasNext()) {
xr.next();
if (xr.getEventType() == START_ELEMENT) {
System.out.println(xr.getLocalName());
if ("car".equals(xr.getLocalName())) {
Car car = xm.readValue(xr, Car.class);
System.out.println(car);
if ("21056".equals(car.getPlate()))
break;
}
}
}
System.out.println("== End Of Process ==");
}
有输出
CarBook
cars
car
WithLazyJackson.Car(model=Alfa Romeo Spider, plate=27437)
car
WithLazyJackson.Car(model=Almera, plate=6429)
car
WithLazyJackson.Car(model=Audi 80 and 90, plate=4898)
car
WithLazyJackson.Car(model=Audi A3, plate=21259)
car
WithLazyJackson.Car(model=Audi A4, plate=21056)
== End Of Process ==
在 19.800.000 辆中只读取了 5 辆汽车