XmlMapper解析XML为JsonNode后,遍历transaction节点获取子节点异常的问题
你遇到的这个问题我之前也碰到过,核心是XmlMapper对单个XML节点和数组节点的处理逻辑差异导致的,咱们一步步来梳理解决:
首先先提个小问题,你的XML代码里有个标签闭合错误:<order_ID>Test123456789</transaction_id>,这里的闭合标签应该是</order_ID>,先修正这个问题,不然解析时可能会出现额外异常。正确的XML结构应该是:
<order> <order_ID>Test123456789</order_ID> <original_inception_date>2024-09-25</original_inception_date> <transaction> <effective_date>2023-12-31 00:00:00.000</effective_date> <transaction_id>1a123456a1234a12345678ab12a1a12a</transaction_id> <product>123</product> <company>1</company> <lob>LIFE</lob> </transaction> </order>
问题原因分析
当XML中只有单个<transaction>节点时,XmlMapper默认会将其解析为单个JsonNode对象,而不是JsonArray(数组)。这时候你用for(JsonNode forNode : node.get("transaction"))进行遍历,实际上是在遍历这个transaction节点的子节点(也就是effective_date、transaction_id这些字段节点),所以第一个forNode就是effective_date的节点,后续调用forNode.get("transaction_id")自然会找不到对应节点,抛出异常。
另外还有个细节:你代码里写的node.get("order_id"),但XML中的标签是<order_ID>,大小写必须严格匹配,否则会获取到null,这也是容易踩的坑。
解决方案
根据你的业务场景,有两种处理方式:
方式一:兼容单个/多个transaction节点
如果你的XML可能存在多个<transaction>节点,希望不管是单个还是多个都按数组逻辑处理,可以通过配置XmlMapper或者手动判断节点类型来实现:
XmlMapper xmlMapper = new XmlMapper(); // 全局配置:允许将单个值解析为数组,这样单个transaction也会被解析成数组 xmlMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY); JsonNode node = xmlMapper.readTree(xmlString); JsonNode transactions = node.get("transaction"); for(JsonNode forNode : transactions) { // 注意order_ID的大小写匹配 policyID = node.get("order_ID").asText(); originalInceptionDate = node.path("original_inception_date").asText(); transactionEffectiveDate = forNode.get("effective_date").asText(); policyTransactionID = forNode.get("transaction_id").asText(); product = forNode.get("product").asText(); company = forNode.get("company").asText(); lob = forNode.get("lob").asText(); // 执行你的业务逻辑 }
如果不想全局配置,也可以手动判断节点是否为数组,再包装:
XmlMapper xmlMapper = new XmlMapper(); JsonNode node = xmlMapper.readTree(xmlString); JsonNode transactionNode = node.get("transaction"); // 手动处理单个节点的情况 JsonNode transactions; if (transactionNode.isArray()) { transactions = transactionNode; } else { transactions = xmlMapper.createArrayNode().add(transactionNode); } // 后续遍历逻辑同上
方式二:确定只有单个transaction节点
如果你的业务中XML永远只会有一个<transaction>节点,那完全不需要for循环,直接获取transaction节点后读取子字段即可:
XmlMapper xmlMapper = new XmlMapper(); JsonNode node = xmlMapper.readTree(xmlString); JsonNode transactionNode = node.get("transaction"); policyID = node.get("order_ID").asText(); originalInceptionDate = node.path("original_inception_date").asText(); transactionEffectiveDate = transactionNode.get("effective_date").asText(); policyTransactionID = transactionNode.get("transaction_id").asText(); product = transactionNode.get("product").asText(); company = transactionNode.get("company").asText(); lob = transactionNode.get("lob").asText();
内容来源于stack exchange

