简体   繁体   English

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

[英]How to convert XML to JSON using only Jackson?

I am getting a response from server as XML.我收到来自服务器的 XML 响应。 But I need to display this in JSON format.但我需要以 JSON 格式显示它。

Is there any way to convert it without any third party API?有没有办法在没有任何第三方 API 的情况下转换它? I used Jackson but for this I need to create POJO.我使用了 Jackson,但为此我需要创建 POJO。

The response from server is like this:来自服务器的响应是这样的:

<?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>

Using Jackson 2.x 使用Jackson 2.x

You can do that with Jackson and no POJOs are required for that: 你可以用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);

The following dependencies are required: 需要以下依赖项:

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

Be aware of the XmlMapper limitations stated in the documentation : 请注意文档中声明的XmlMapper限制:

Tree Model is only supported in limited fashion: specifically, Java arrays and Collections can be written, but can not be read, since it is not possible to distinguish Arrays and Objects without additional information. 树模型仅以有限的方式支持:具体而言,Java数组和Collections可以编写,但无法读取,因为在没有附加信息的情况下无法区分数组和对象。

Using JSON.org 使用JSON.org

You also can do it with 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();

The following dependency is required: 需要以下依赖项:

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

I know that I am too late for an answer here. 我知道我来这里的答案太迟了。 But I am writing this for the new guys who stumbled upon this question and thinking to use @Cassio's answer. 但是我正在为那些偶然发现这个问题并想着使用@Cassio答案的新人写这篇文章。

The problem of using XmlMpper to de-serialize to a JsonNode is that, when there are multiple elements with the same name at the same level, then it will replace the previous one with the new one and end up with data loss. 使用XmlMpper反序列化为JsonNode是,当同一级别有多个具有相同名称的元素时,它将用新的元素替换前一个元素,最终导致数据丢失。 Usually, we've to add this to an array. 通常,我们要将其添加到数组中。 To tackle this problem, we can override the _handleDuplicateField() method of the JsonNodeDeserializer class. 要解决此问题,我们可以覆盖JsonNodeDeserializer类的_handleDuplicateField()方法。 Enough talking. 够说话了。 Let's see the code 我们来看看代码

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

Since we've overridden the default deserializer, we also need to register this in the XmlMapper to make it work. 由于我们已经重写了默认的反序列化器,我们还需要在XmlMapper注册它以使其工作。

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

Is there any way to convert xml to json without using any third party API? 有没有办法在不使用任何第三方API的情况下将xml转换为json?

If you are being practical, no there isn't. 如果你是实际的,没有。

The step of parsing the XML can be performed using APIs that are part of Java SE. 解析XML的步骤可以使用作为Java SE一部分的API来执行。 However going from the parsed XML (eg a DOM) to JSON requires a JSON support library, and Java SE does not include one. 但是,从解析的XML(例如DOM)到JSON需要JSON支持库,而Java SE不包含JSON。

(In theory you could write such a library yourself, but what is the point of doing that?) (理论上你可以自己编写这样一个库,但这样做有什么意义呢?)


I used Jackson but for this I need to create POJO. 我用过杰克逊,但为此我需要创建POJO。

@Cassio points out that Jackson allows you to do this translation without writing POJOs. @Cassio指出杰克逊允许你在不编写POJO的情况下进行翻译。 Alternatively, look at other (3rd-party) JSON APIs for Java; 或者,查看Java的其他(第三方)JSON API; see http://www.json.org for a list of alternatives. 请参阅http://www.json.org以获取备选方案列表。 Some of the simpler ones don't involve defining POJOs 一些较简单的不涉及定义POJO

Using jackson 使用杰克逊

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 "";
        }
    }
}
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();
        }
    }
}

I have just followed cassiomolin steps. 我刚刚跟着cassiomolin步骤。 I have faced below exception while using the jackson 2.x libraries. 使用jackson 2.x库时,我遇到了以下异常。

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

If you also face the above exception. 如果您还面临上述异常。 Add the below code to fix the issue. 添加以下代码以解决问题。 Then you can able to see the converted JSON without the namespace. 然后,您可以在没有命名空间的情况下查看转换后的JSON。

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

Tips : If you want to convert the XML without the namespace then use jackson library. 提示:如果要在没有命名空间的情况下转换XML,请使用jackson库。 Dont go for org.json libs. 不要去org.json libs。 It doesnt support this use case. 它不支持这个用例。

According to the author of Jackson, Jackson 2.12 is able to read XML with readTree even with duplicate elements :根据 Jackson 的作者, Jackson 2.12 能够使用 readTree 读取 XML,即使有重复元素

Note: Jackson version 2.12 DOES allow reading of duplicate elements with readTree().注意:Jackson 2.12 版允许使用 readTree() 读取重复元素。 (also works for nominal type of java.lang.Object, so-called "untyped" binding). (也适用于 java.lang.Object 的名义类型,即所谓的“无类型”绑定)。

So you can just use所以你可以使用

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM