【问题标题】:Generate SHA-256 hash for a XML in Java在 Java 中为 XML 生成 SHA-256 哈希
【发布时间】:2017-09-20 04:00:47
【问题描述】:

我正在尝试为 http 请求(对于我的一个项目)添加缓存功能,并且我想使用 Etag 作为哈希值。但如果 Etag 不存在,我想使用有效负载来生成唯一的哈希值。众所周知,相同的 xml 负载可能具有不同的结构。例如样品 A 和样品 B 相同。但它们的字符串结构并不相同。我需要的是一种从两个 xml 样本生成相同哈希键的方法。

样本 A

<note>
   <to>Tove</to>
   <from>Jani</from>
   <heading>Reminder</heading>
   <body>Don't forget me this weekend!</body>
</note>

样本 B

<note>
   <to>Tove</to>
   <heading>Reminder</heading>
   <from>Jani</from>
   <body>Don't forget me this weekend!</body>
</note>

【问题讨论】:

  • 如果顺序在您的应用程序中不重要,您应该将结构标准化为一些规范顺序,然后对其进行哈希处理。
  • 以这种方式规范化 XML 的工作量很大。请参阅数字签名 XML 的标准。但是为什么在您的应用程序中会发生这种情况?为什么服务器生成的 XML 在语义上是等效的,但看起来却完全不同?
  • @OliverCharlesworth 我尝试使用org.w3c.dom.document.normalizeDocument() 方法规范化XML 文档,但每次规范化文档时都不会考虑对象的结构。所以我仍然无法获得具有两种不同结构的两个 XML 有效负载的唯一哈希。
  • 我实际上建议不要打扰。我的感觉是它实际上不会成为问题,因为 XML 将由软件创建,并且软件很可能生成具有相同元素顺序的 XML。如果有一些奇怪的情况可能不会显着影响缓存性能。 (插入关于过早优化的标准建议。)
  • 样本 A 和样本 B 就 XML 而言相同。您的应用程序可能认为它们是等价的,但 XML 不是。所以无论你做什么规范化都将是特定于应用程序的。

标签: java xml hash sha256


【解决方案1】:

org.w3c.dom.document.normalizeDocument() 文档不会改变子元素的顺序。

可以通过文档的递归解析来做到这一点。但是,请考虑这是否比您首先尝试缓存的操作更昂贵......

方法

  • 在每个级别将所有节点复制到java.util.List 实现,即 ArrayList。这是必需的,因为 org.w3c.dom.NodeList 不允许修改
  • 使用Collections.sort()对列表进行排序
  • 从父级中删除子级
  • 按排序顺序重新添加子项

请注意,这并不处理具有不同内容的多个同名元素,但确实解决了您的示例

例如:

public static void main(String[] args) throws Exception {
    Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new File("test.xml"));
    sort(doc);

    TransformerFactory tf = TransformerFactory.newInstance();
    Transformer transformer = tf.newTransformer();
    transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
    StringWriter writer = new StringWriter();
    transformer.transform(new DOMSource(doc), new StreamResult(writer));

    System.out.println(writer);
}

private static void sort(Node doc) {
    List<Node> children = new ArrayList<>();
    for (int i = 0; i < doc.getChildNodes().getLength(); i++) {
        children.add(doc.getChildNodes().item(i));
    }
    for (Node child : children) {
        doc.removeChild(child);
    }
    Collections.sort(children, (a, b) -> {
        return a.getNodeName().compareTo(b.getNodeName());
    });
    for (Node child : children) {
        doc.appendChild(child);
    }
    for (Node child : children) {
        sort(child);
    }
}

【讨论】:

  • 像魅力一样工作。谢谢。
猜你喜欢
  • 2014-08-19
  • 1970-01-01
  • 2011-04-18
  • 2011-03-22
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 2011-03-07
  • 2013-01-09
相关资源
最近更新 更多