如何仅使用 Jackson 将 XML 转换为 JSON?

2022-09-02 11:19:25

我从服务器收到XML响应。但我需要以JSON格式显示它。

有没有办法在没有任何第三方API的情况下转换它?我使用了Jackson,但为此我需要创建POJO。

来自服务器的响应如下所示:

<?xml version='1.0'?>
<errors><error><status>400</status><message>The field 'quantity' is invalid.</message><details><invalid_reason>The quantity specified is greater than the quantity of the product that is available to ship.</invalid_reason><available_quantity>0</available_quantity><order_product_id>12525</order_product_id></details></error></errors>

答案 1

使用 Jackson 2.x

你可以用Jackson做到这一点,并且不需要POJO:

String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
             "<errors>\n" +
             "  <error>\n" +
             "    <status>400</status>\n" +
             "    <message>The field 'quantity' is invalid.</message>\n" +
             "    <details>\n" +
             "      <invalid_reason>The quantity specified is greater than the quantity of the product that is available to ship.</invalid_reason>\n" +
             "      <available_quantity>0</available_quantity>\n" +
             "      <order_product_id>12525</order_product_id>\n" +
             "    </details>\n" +
             "  </error>\n" +
             "</errors>";

XmlMapper xmlMapper = new XmlMapper();
JsonNode node = xmlMapper.readTree(xml.getBytes());

ObjectMapper jsonMapper = new ObjectMapper();
String json = jsonMapper.writeValueAsString(node);

需要以下依赖项:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.8.2</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.8.2</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.8.2</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.8.2</version>
</dependency>

请注意文档中所述的限制:XmlMapper

树模型仅以有限的方式受支持:具体来说,Java数组可以写入,但不能读取,因为如果没有其他信息,就不可能区分数组和对象。Collections

正如 Jackson 作者在注释中很好地强调的那样,Jackson 2.12 最终改进了 XML 处理,以便在使用 或 作为目标类型保留重复项。JsonNodeObject

使用 JSON.org

您也可以使用 JSON.org 执行此操作:

String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
             "<errors>\n" +
             "  <error>\n" +
             "    <status>400</status>\n" +
             "    <message>The field 'quantity' is invalid.</message>\n" +
             "    <details>\n" +
             "      <invalid_reason>The quantity specified is greater than the quantity of the product that is available to ship.</invalid_reason>\n" +
             "      <available_quantity>0</available_quantity>\n" +
             "      <order_product_id>12525</order_product_id>\n" +
             "    </details>\n" +
             "  </error>\n" +
             "</errors>";

String json = XML.toJSONObject(xml).toString();

需要以下依赖项:

<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20160810</version>
</dependency>

答案 2

我知道我来不及在这里回答。但是我是为那些偶然发现这个问题并想使用@Cassio答案的新人写这篇文章的。

使用 反序列化为 的问题是,当在同一级别上有多个具有相同名称的元素时,它将用新元素替换前一个元素,并最终导致数据丢失。通常,我们必须将其添加到数组中。为了解决这个问题,我们可以覆盖类的方法。足够多的谈话。让我们看看代码XmlMpperJsonNode_handleDuplicateField()JsonNodeDeserializer

public class DuplicateToArrayJsonNodeDeserializer extends JsonNodeDeserializer {

    @Override
    protected void _handleDuplicateField(JsonParser p, DeserializationContext ctxt, 
        JsonNodeFactory nodeFactory,String fieldName, ObjectNode objectNode,
        JsonNode oldValue, JsonNode newValue) throws JsonProcessingException {
        ArrayNode node;
        if(oldValue instanceof ArrayNode){
            node = (ArrayNode) oldValue;
            node.add(newValue);
        } else {
            node = nodeFactory.arrayNode();
            node.add(oldValue);
            node.add(newValue);
        }
        objectNode.set(fieldName, node);
    }
}

由于我们已经覆盖了默认的反序列化程序,因此我们还需要在 中注册此反序列化程序以使其正常工作。XmlMapper

XmlMapper xmlMapper = new XmlMapper();
xmlMapper.registerModule(new SimpleModule().addDeserializer(
    JsonNode.class, 
    new DuplicateToArrayJsonNodeDeserializer()
));
JsonNode node = xmlMapper.readTree(payLoad);