我使用jackson-dataformat-xml(2.9)将XML解析为JSONode,然后将其解析为JSON(XML是非常动态的,所以我使用JSONode而不是绑定到POJO。例如,“元素名”和“id”的名称可能不同)。
在JSON解析阶段,其中一个元素键是空字符串(“”)。
XML:
<elementName>
<id type="pid">abcdef123</id>
</elementName>
public Parser() {
ObjectMapper jsonMapper = new ObjectMapper();
XmlMapper xmlMapper = new XmlMapper(new XmlFactory(new WstxInputFactory()));
}
public InputStream parseXmlResponse(InputStream xmlStream) {
InputStream stream = null;
try {
JsonNode node = xmlMapper.readTree(xmlStream);
stream = new ByteArrayInputStream(jsonMapper.writer().writeValueAsBytes(node));
} catch (IOException e) {
e.printStackTrace();
}
return stream;
}
JSON:
结果:
{
"elementName": {
"id": {
"type": "pid",
"": "abcdef123"
}
},
}
预期:
{
"elementName": {
"id": {
"type": "pid",
"value": "abcdef123"
}
},
}
我的想法是无论何时找到空密钥“”,并用“值”替换它。无论是在XML反序列化还是在JSON序列化期间。我尝试使用默认的序列化程序,筛选器,但没有使它以一种良好和简洁的方式工作。
非常感谢提出建议。
基于@Shoek的建议,我决定编写一个自定义序列化程序,以避免在过程中创建中间对象(ObjectNode)。
public class CustomNode {
private JsonNode jsonNode;
public CustomNode(JsonNode jsonNode) {
this.jsonNode = jsonNode;
}
public JsonNode getJsonNode() {
return jsonNode;
}
}
public class CustomObjectsResponseSerializer extends StdSerializer<CustomNode> {
protected CustomObjectsResponseSerializer() {
super(CustomNode.class);
}
@Override
public void serialize(CustomNode node, JsonGenerator jgen, SerializerProvider provider) throws IOException {
convertObjectNode(node.getJsonNode(), jgen, provider);
}
private void convertObjectNode(JsonNode node, JsonGenerator jgen, SerializerProvider provider) throws IOException {
jgen.writeStartObject();
for (Iterator<String> it = node.fieldNames(); it.hasNext(); ) {
String childName = it.next();
JsonNode childNode = node.get(childName);
// XML parser returns an empty string as value name. Replacing it with "value"
if (Objects.equals("", childName)) {
childName = "value";
}
if (childNode instanceof ArrayNode) {
jgen.writeFieldName(childName);
convertArrayNode(childNode, jgen, provider);
} else if (childNode instanceof ObjectNode) {
jgen.writeFieldName(childName);
convertObjectNode(childNode, jgen, provider);
} else {
provider.defaultSerializeField(childName, childNode, jgen);
}
}
jgen.writeEndObject();
}
private void convertArrayNode(JsonNode node, JsonGenerator jgen, SerializerProvider provider) throws IOException {
jgen.writeStartArray();
for (Iterator<JsonNode> it = node.elements(); it.hasNext(); ) {
JsonNode childNode = it.next();
if (childNode instanceof ArrayNode) {
convertArrayNode(childNode, jgen, provider);
} else if (childNode instanceof ObjectNode) {
convertObjectNode(childNode, jgen, provider);
} else {
provider.defaultSerializeValue(childNode, jgen);
}
}
jgen.writeEndArray();
}
}
您还可以简单地对JSON DOM进行后处理,遍历所有对象,并将空字符串的键重命名为“value”。
争用条件:这样的密钥可能已经存在,并且不能覆盖
(例如
)。
用法:
(注意:您不应该静默地禁止异常并返回null,而是允许它传播,以便调用方可以决定在需要时捕获并应用故障转移逻辑)
public InputStream parseXmlResponse(InputStream xmlStream) throws IOException {
JsonNode node = xmlMapper.readTree(xmlStream);
postprocess(node);
return new ByteArrayInputStream(jsonMapper.writer().writeValueAsBytes(node));
}
private void postprocess(JsonNode jsonNode) {
if (jsonNode.isArray()) {
ArrayNode array = (ArrayNode) jsonNode;
Iterable<JsonNode> elements = () -> array.elements();
// recursive post-processing
for (JsonNode element : elements) {
postprocess(element);
}
}
if (jsonNode.isObject()) {
ObjectNode object = (ObjectNode) jsonNode;
Iterable<String> fieldNames = () -> object.fieldNames();
// recursive post-processing
for (String fieldName : fieldNames) {
postprocess(object.get(fieldName));
}
// check if an attribute with empty string key exists, and rename it to 'value',
// unless there already exists another non-null attribute named 'value' which
// would be overwritten.
JsonNode emptyKeyValue = object.get("");
JsonNode existing = object.get("value");
if (emptyKeyValue != null) {
if (existing == null || existing.isNull()) {
object.set("value", emptyKeyValue);
object.remove("");
} else {
System.err.println("Skipping empty key value as a key named 'value' already exists.");
}
}
}
}
输出:正如预期的那样。
{
"elementName": {
"id": {
"type": "pid",
"value": "abcdef123"
}
},
}
编辑:关于性能的注意事项:
我使用一个大型XML文件(enwikiquote-20200520-pages-articles-multistream.XML
,en.wikiquote XML dump,498.4 MB)进行了100轮测试,测试时间如下(使用deltas与system.nanotime()
):
jsonnode=xmlmapper.readtree(xmlStream);
)后处理(节点);
)new ByteArrayInputStream(jsonMapper.writer().writeValueasBytes(node));
)对于从一个大约500 MB的文件构建对象树来说,这只是一毫秒的几分之一--因此性能非常出色,无需担心。
我有以下,每个都有几个元素: 我打算让变量包含、或类型的元素。我尝试将类型的元素添加到中,如下所示: 但是IDE不允许我这样做,它说: 我是否使用了?我如何解决这个问题?
问题内容: 我正在使用Java,我创建了一个枚举,如下所示: 上面的示例在以元素名称(即北美)使用空格时给出了错误。有什么建议可以解决上述问题吗? 问题答案: 您不能在标识符中间放置空格。 这样做结束了标识符,并且解析器假定接下来要执行的操作是该语句上下文中的有效令牌。很少(如果有)合法的地方。 常规的Java值名称为: 一个可以具有相关属性,如人类可读的名称,例如, 我对用于提供表示层表示形式有
我想根据元素的数据集过滤元素。我创建了一个小提琴来显示我所处的位置:这里,但如你所见,当我选择“红色”时,它只是隐藏了“红色”项,而不是其他项。就像“黄色”一样,它不会做任何事情。 下面是脚本: 多谢!
本文向大家介绍什么是空元素?常用的空元素有哪些?相关面试题,主要包含被问及什么是空元素?常用的空元素有哪些?时的应答技巧和注意事项,需要的朋友参考一下 没有闭合标签的元素是空元素
问题内容: 在命令提示符下运行项目时,出现以下错误 我收到以下错误 来源:com / javavids / jaxb / sitemap / UPM / Test.java 来源:com / javavids / jaxb / sitemap / UPM / ObjectFactory.java 来源:com / javavids / jaxb / sitemap / main / Main.ja
我有一个问题与我的震动转换,但不知道如何解决它。我在生成的数组中获得“null”元素: 我的结果: