如何使用 Jackson 通过流 API 解析 XML 文件

Pap*_*zzo 2 java json jackson jackson-dataformat-xml

我正在寻找一种使用 kotlin 解析大型 xml 的方法。

我常用的 JSON 解析器是 Jackson,我知道它也可以用来解析 xml。

源文件太大,无法使用 DOM 方法进行解析,我必须使用流 API。我可以找到几个关于如何将 Jackson Streaming API 与 JSON 结合使用的示例,但没有找到关于 XML 的示例。文档https://github.com/FasterXML/jackson-dataformat-xml

尽管模块实现了低级(JsonFactory / JsonParser / JsonGenerator)抽象,但大多数使用都是通过数据绑定级别。这是因为在数据绑定级别添加了少量解决方法,以解决 XML 特性:

这让我担心这个库的 XML 流方法是否可行和/或支持。

jos*_*uan 5

读取树结构需要进程启动(例如<element>对于XMLJSON{ / [这种方式在以流方式处理时不可能读取整个对象。

\n

让根包装器和一个大的汽车列表(为简洁起见,我使用 lombok 注释):

\n
@Getter\n@Setter\n@JacksonXmlRootElement\n@NoArgsConstructor\n@AllArgsConstructor\nstatic class CarBook {\n    @JacksonXmlProperty(isAttribute = true)\n    private int version;\n    @JacksonXmlElementWrapper(localName = "cars")\n    @JacksonXmlProperty(localName = "car")\n    private List<Car> cars;\n}\n\n@Getter\n@Setter\n@ToString\n@NoArgsConstructor\n@AllArgsConstructor\nstatic class Car {\n    private String model;\n    private String plate;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

那么,你无法得到CarBook在所有列表(可能是其他成员)被完全读取之前,您无法获取对象。

\n

通常的方法是使用 aXMLStreamReader并逐个检查您得到的令牌,但您可以使用 jackson 来解析整个对象XmlMapper方法解析整个对象:

\n
/**\n * Method for reading a single XML value from given XML-specific input\n * source; useful for incremental data-binding, combining traversal using\n * basic Stax {@link XMLStreamReader} with data-binding by Jackson.\n * \n * @since 2.4\n */\npublic <T> T readValue(XMLStreamReader r, Class<T> valueType) throws IOException {\n    return readValue(r, _typeFactory.constructType(valueType));\n} \n
Run Code Online (Sandbox Code Playgroud)\n

举个例子,让大(1,2G)文件:

\n
<CarBook version="1"><cars>\n<car><model>Alfa Romeo Spider</model><plate>27437</plate></car>\n<car><model>Almera</model><plate>6429</plate></car>\n<car><model>Audi 80 and 90</model><plate>4898</plate></car>\n<car><model>Audi A3</model><plate>21259</plate></car>\n<car><model>Audi A4</model><plate>21056</plate></car>\n<car><model>Audi Coup\xc3\xa9</model><plate>5623</plate></car>\n<car><model>Austin Metro</model><plate>26446</plate></car>\n<car><model>BMW 3 Series</model><plate>16338</plate></car>\n<car><model>BMW 5 Series</model><plate>29859</plate></car>\n...\n
Run Code Online (Sandbox Code Playgroud)\n

的,你可以懒惰地阅读

\n
public static void main(String... args) throws IOException, XMLStreamException {\n    XmlMapper xm = new XmlMapper();\n    XMLInputFactory xif = XMLInputFactory.newInstance();\n    XMLStreamReader xr = xif.createXMLStreamReader(new FileInputStream(/* 1,2G file */ "/home/josejuan/tmp/all.cars.xml"));\n\n    // you must to read step by step\n    while (xr.hasNext()) {\n        xr.next();\n        if (xr.getEventType() == START_ELEMENT) {\n            System.out.println(xr.getLocalName());\n            if ("car".equals(xr.getLocalName())) {\n                Car car = xm.readValue(xr, Car.class);\n                System.out.println(car);\n                if ("21056".equals(car.getPlate()))\n                    break;\n            }\n        }\n    }\n\n    System.out.println("== End Of Process ==");\n}\n
Run Code Online (Sandbox Code Playgroud)\n

带输出

\n
CarBook\ncars\ncar\nWithLazyJackson.Car(model=Alfa Romeo Spider, plate=27437)\ncar\nWithLazyJackson.Car(model=Almera, plate=6429)\ncar\nWithLazyJackson.Car(model=Audi 80 and 90, plate=4898)\ncar\nWithLazyJackson.Car(model=Audi A3, plate=21259)\ncar\nWithLazyJackson.Car(model=Audi A4, plate=21056)\n== End Of Process ==\n
Run Code Online (Sandbox Code Playgroud)\n

仅读取 19.800.000 辆汽车中的 5 辆

\n