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

Posted

技术标签:

【中文标题】如何仅使用 Jackson 将 XML 转换为 JSON?【英文标题】:How to convert XML to JSON using only Jackson? 【发布时间】:2017-01-22 10:06:30 【问题描述】:

我收到来自服务器的 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>

【问题讨论】:

该服务器是否也支持application/json 顺便说一句,Jackson 也有一个 XML 转换器 是的.. 当我这样发布时:httpPost.setEntity(new StringEntity(aobj, ContentType.create("application/json")));响应= httpclient.execute(目标,httpPost);我收到了 xml 格式表单服务器的成功或失败响应。 @cricket_007 但我不想为此创建 pojo 类.. 成功时它向我发送了成功消息,失败时它向我发送了错误消息。 我不确定这个问题是否真的跑题了。 OP 没有要求我们推荐或查找书籍、工具、软件库、教程或其他场外资源。他们询问是否有任何方法可以将 XML 转换为 JSON无需任何第三方 API 【参考方案1】:

据杰克逊的作者Jackson 2.12 is able to read XML with readTree even with duplicate elements:

注意:Jackson 2.12 版允许使用 readTree() 读取重复元素。 (也适用于 java.lang.Object 的标称类型,即所谓的“无类型”绑定)。

所以你可以使用

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

【讨论】:

【参考方案2】:

使用杰克逊 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>

注意documentation 中所述的XmlMapper 限制:

树模型仅以有限的方式支持:具体来说,Java 数组和Collections 可以写入,但不能读取,因为没有附加信息就无法区分数组和对象.

正如Jackson author in the comments 很好地突出显示的那样,Jackson 2.12 最后是improved XML handling,以便if 使用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>

【讨论】:

@samunp 只是让您知道,Jackson 2.x 的 XML 支持作为单独的工件发布。换句话说,即使您使用 Jackson 2.x,如果您想使用 XmlMapper,也需要包含 jackson-dataformat-xml 依赖项。 这是我在这个网站上看到的关于 MIME 转换的唯一一个相当连贯的答案之一。谢谢。 Jackson 选项的大警告是 XML 通常具有重复键,当 Jackson 将具有重复键的 XML 转换为 JSON 时,它们将被覆盖。 上述警告是合法的,但请注意,Jackson 2.12 最终改进了处理方式(参见cowtowncoder.medium.com/jackson-2-12-improved-xml-b9487889a23f),因此如果使用JsonNodeObject 作为目标类型,则会保留重复项。 不错,@StaxMan!我刚刚将此注释添加到我的答案中。感谢您的评论和杰克逊的所有工作。【参考方案3】:

我刚刚完成了 cassiomolin 步骤。我在使用 jackson 2.x 库时遇到了以下异常。

Cannot create XMLStreamReader or XMLEventReader from a org.codehaus.stax2.io.Stax2ByteArraySource

如果你也遇到上述异常。添加以下代码以解决此问题。然后你可以看到没有命名空间的转换后的 JSON。

JacksonXmlModule module = new JacksonXmlModule();
module.setDefaultUseWrapper(false);
XmlMapper xmlMapper = new XmlMapper(module);

提示: 如果要在没有命名空间的情况下转换 XML,请使用 jackson 库。不要去 org.json 库。它不支持这个用例。

【讨论】:

【参考方案4】:

使用杰克逊

import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import java.io.IOException;

public class JsonUtil 

    private static XmlMapper XML_MAPPER = new XmlMapper();
    private static ObjectMapper JSON_MAPPER = new ObjectMapper();

    public static ObjectMapper getJsonMapper()
        return JSON_MAPPER;
    

    public static XmlMapper getXmlMapper()
        return XML_MAPPER;
    

    public static String xmlToJson(String xml)
        try 
            return getJsonMapper().writeValueAsString(getXmlMapper().readTree(xml));
         catch (IOException e) 
            e.printStackTrace();
            return "";
        
    

【讨论】:

【参考方案5】:

我知道我在这里回答太晚了。但我正在为那些偶然发现这个问题并考虑使用@Cassio 答案的新人写这篇文章。

使用XmlMpper反序列化为JsonNode的问题是,当同一层级有多个同名元素时,会用新的元素替换前一个元素并结束与数据丢失。通常,我们必须将其添加到数组中。为了解决这个问题,我们可以重写JsonNodeDeserializer 类的_handleDuplicateField() 方法。说够了。看代码

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);

【讨论】:

很棒的答案! 非常好!另请注意,从以上 Jackson 2.12 开始,也由 XML 模块完成(参见cowtowncoder.medium.com/jackson-2-12-improved-xml-b9487889a23f)【参考方案6】:
package com.src.test;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

import org.apache.commons.io.IOUtils;

import net.sf.json.JSON;
import net.sf.json.xml.XMLSerializer;

public class JSONConverter 
    private static URL url = null;
    private static InputStream input = null;

    public static void main(String args[]) throws IOException 
        try 
            url = JSONConverter.class.getClassLoader().getResource("sampleXmlFilePath.xml");
            input = url.openStream();
            String xmlData = IOUtils.toString(input);

            XMLSerializer xmlSerializer = new XMLSerializer();
            JSON json = xmlSerializer.read(xmlData);
            System.out.println("JSON format : " + json);
         catch (Exception e) 
            e.printStackTrace();
         finally 
            input.close();
        
    

【讨论】:

【参考方案7】:

有什么方法可以在不使用任何第三方 API 的情况下将 xml 转换为 json?

如果你是实际的,没有。

解析 XML 的步骤可以使用作为 Java SE 一部分的 API 来执行。然而,从解析的 XML(例如 DOM)到 JSON 需要 JSON 支持库,而 Java SE 不包含。

(理论上您可以自己编写这样一个库,但这样做有什么意义?)


我使用了 Jackson,但为此我需要创建 POJO。

@Cassio 指出 Jackson 允许您在不编写 POJO 的情况下进行此翻译。或者,查看其他(第 3 方)Java 的 JSON API;请参阅http://www.json.org 以获取替代列表。一些更简单的不涉及定义 POJO

【讨论】:

以上是关于如何仅使用 Jackson 将 XML 转换为 JSON?的主要内容,如果未能解决你的问题,请参考以下文章

使用jackson转换xml格式数据进行响应

使用 jackson-dataformat-xml 库将 XML 中的空标签转换为 java 属性

如何在全球范围内配置带弹簧的jackson?

使用 Jackson 将 Map 转换为 JSON

使用Jackson – 将字符串转换为 JsonNode 对象

将JSON转换为Java Object,如何使用Jackson解析BadgerFish约定