如何仅使用 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 使用JsonNode
或Object
作为目标类型保留重复项.
使用 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),因此如果使用JsonNode
或Object
作为目标类型,则会保留重复项。
不错,@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-dataformat-xml 库将 XML 中的空标签转换为 java 属性