使用FasterXML解析多层嵌套XML时能否避免创建额外类?
解析多层嵌套XML又不想写一堆POJO?试试这几个方法
问题背景
要解析的XML是多层嵌套结构,每一层只有一个子元素,示例结构如下:
<xml> <level1> <level2> <level3> <actualData>123</actualData>
本来想用@JacksonXmlElementWrapper跳过包装类,但这个注解的localName只能传单个值,没法像下面这种无效写法那样指定多层路径:
@JacksonXmlElementWrapper(localName = ["level1", "level2", "level3"]) // 无效写法,localName只接受单个参数 @JacksonXmlProperty(localName = "actualData") private String actualData;
需求很明确:解析这个嵌套XML,但不想为level1、level2、level3单独写POJO类。
可行方案
1. 直接用路径表达式(Jackson 2.12+)
Jackson从2.12版本开始支持在@JacksonXmlProperty里用点分隔的完整路径,一步到位指定嵌套层级,完全不用额外POJO:
@JacksonXmlRootElement(localName = "xml") public class XmlData { @JacksonXmlProperty(localName = "level1.level2.level3.actualData") private String actualData; // 别忘了加getter和setter public String getActualData() { return actualData; } public void setActualData(String actualData) { this.actualData = actualData; } }
解析的时候正常用XmlMapper就行:
XmlMapper mapper = new XmlMapper(); XmlData data = mapper.readValue(xmlContent, XmlData.class);
这个方法最简单,只要版本够就优先用。
2. 自定义反序列化器(兼容低版本Jackson)
如果你的Jackson版本低于2.12,那就自己写个反序列化器,手动遍历XML节点:
@JacksonXmlRootElement(localName = "xml") public class XmlData { @JsonDeserialize(using = NestedDataDeserializer.class) private String actualData; // getter和setter } class NestedDataDeserializer extends JsonDeserializer<String> { @Override public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { XmlParser xmlParser = (XmlParser) p; // 一层一层找节点 xmlParser.nextTag(); if (!"level1".equals(xmlParser.getCurrentName())) { throw new IOException("找不到<level1>标签"); } xmlParser.nextTag(); if (!"level2".equals(xmlParser.getCurrentName())) { throw new IOException("找不到<level2>标签"); } xmlParser.nextTag(); if (!"level3".equals(xmlParser.getCurrentName())) { throw new IOException("找不到<level3>标签"); } xmlParser.nextTag(); if (!"actualData".equals(xmlParser.getCurrentName())) { throw new IOException("找不到<actualData>标签"); } return xmlParser.getText(); } }
虽然代码啰嗦点,但能兼容老版本,完全可控。
3. 用树模型直接取数
不想改POJO的话,还可以用Jackson的树模型先把整个XML解析成JsonNode,再通过路径直接拿值:
XmlMapper mapper = new XmlMapper(); JsonNode root = mapper.readTree(xmlContent); String actualData = root.path("level1").path("level2").path("level3").path("actualData").asText();
这种方式最灵活,不用定义任何注解,适合临时解析或者XML结构偶尔变动的场景。
内容的提问来源于stack exchange,提问作者Mateus Ramos
相关产品推荐
相关产品推荐

