【问题标题】:How to convert XML to JSON using only Jackson?如何仅使用 Jackson 将 XML 转换为 JSON?
【发布时间】: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

标签: java json xml jackson


【解决方案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);
        

        【讨论】:

        【解决方案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

          【讨论】:

            猜你喜欢
            • 2014-01-31
            • 2020-03-15
            • 2018-12-08
            • 2017-02-01
            • 2018-03-02
            • 2019-01-06
            • 2015-06-03
            • 2019-01-04
            相关资源
            最近更新 更多