【问题标题】:Handling empty XML nodes when converting to JSON using Jackson使用 Jackson 转换为 JSON 时处理空 XML 节点
【发布时间】:2019-08-20 02:50:18
【问题描述】:

我读入了一个 XML 文件(由另一个系统提供,所以我无法控制它)以便将其转换为 JSON。使用杰克逊。我看到一些不良行为,其中源 XML 文件中的任何“空”节点都被转换为 JSON,内容为“\n ”。例如:

生成的输出:

{"a":"Dummy Content","b":"\n "}

期望的输出:

{"a":"Dummy Content","b":""}

以一种足够通用的方式更正此问题的最可接受的方法是什么,它适用于具有任何空 XML 节点的任何 XML 文件?

加载文件时,我尝试迭代每一行以清除它,如下所示:

String content = "";
try (BufferedReader br = new BufferedReader(new FileReader("MyFile.xml"))) {
    String line;
    while ((line = br.readLine()) != null) {
        content += line.replace(System.getProperty("line.separator"), "").trim();
    }
}

它似乎有效,但我想知道是否有更好的解决方案?源 XML 文件可能非常大(数十万行)。

说明问题的示例代码

private static String testXML
    = "<Root>\n"
    + " <a>Dummy Content</a>\n"
    + " <b>\n"
    + " </b>\n"
    + "</Root>";

public static void main(String[] args) {
    XmlMapper xmlMapper = new XmlMapper();
    JsonNode jsonNode = null;
    try {
        jsonNode = xmlMapper.readTree(testXML);
    } catch (IOException ex) {
        System.out.println(ex);
    }
    System.out.println(jsonNode);
}

生成的输出:

{"a":"Dummy Content","b":"\n "}

期望的输出:

{"a":"Dummy Content","b":""}

【问题讨论】:

标签: java json xml jackson deserialization


【解决方案1】:

如果您将XML 反序列化为JsonNode,您可以覆盖JsonNodeFactory,它会创建带有数据的节点。对于String,我们需要覆盖textNode 方法,如果值is blank,则只需trim it to emptyString

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.TextNode;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.apache.commons.lang3.StringUtils;

public class XmlApp {

  public static void main(String[] args) throws Exception {
    String testXML = "<Root>\n <a>Dummy Content</a>\n <b>\n </b>\n</Root>";

    XmlMapper xmlMapper = new XmlMapper();
    xmlMapper.setNodeFactory(new TrimStringTextJsonNodeFactory());

    JsonNode jsonNode = xmlMapper.readTree(testXML);

    System.out.println(jsonNode);
  }
}

class TrimStringTextJsonNodeFactory extends JsonNodeFactory {

  @Override
  public TextNode textNode(String text) {
    if (StringUtils.isBlank(text)) {
      text = StringUtils.trimToEmpty(text);
    }
    return super.textNode(text);
  }
}

上面的代码打印:

{"a":"Dummy Content","b":""}

【讨论】:

  • 这看起来效果很好!我知道 Jackson 内部必须有一个解决方案,但这是我第一次使用它,所以感谢这个解决方案。
【解决方案2】:

您可以先将所有特殊字符替换为空一个:

testXml = testXml.replaceAll('\n', '');

【讨论】:

  • 正确,这将删除换行符,但在任何缩进中留下空白。即:{“a”:“虚拟内容”,“b”:“”}。我需要一些让属性真正为空的东西。
【解决方案3】:

在将 XML 转换为 JSON 之前,对 XML 应用 XSLT 转换。您不能指望通用库进行语义转换(例如将“\n”和“”视为等效)。您需要在 XML 到 JSON 的转换之前或之后将其作为一个单独的步骤执行,并且之前执行此操作更容易,因为有更多可用的工具。

在解析之前不要尝试对词法 XML 进行转换:您可能会破坏 XML。例如,删除分隔开始标记中两个属性的换行符会产生格式错误的 XML。

【讨论】:

  • 我在 XSLT 方面的经验非常有限,请问有什么例子吗?
猜你喜欢
  • 2017-02-01
  • 2014-07-16
  • 2020-03-12
  • 1970-01-01
  • 1970-01-01
  • 2017-01-22
  • 1970-01-01
  • 2020-03-15
  • 1970-01-01
相关资源
最近更新 更多