【问题标题】:How to get all xpaths from a XSD?如何从 XSD 获取所有 xpath?
【发布时间】:2015-06-30 13:31:40
【问题描述】:

我有一个 XSD,要求将 XSD 中存在的所有元素的 xpath 列出到 UI 中,以便用户可以使用它来执行一些与 DOM 相关的操作。

我能否以编程方式从 XSD 中提取所有元素的 xpath?

【问题讨论】:

  • 模式语言很复杂,允许maxOccurs="unbounded" 之类的东西或递归,这意味着实例文档可以包含的元素数量不受限制,您希望如何能够提取 XPath 表达式所有元素?还有一个元素的路径是什么,因为可以有多种方法来选择某个节点。
  • 我不完全清楚这个问题是否询问 XSD xml 文档本身中存在的元素的 xpath,或者更确切地说,可能在 xml 中找到的所有可能 xpath 的列表XSD 描述的文档。我将尝试在下面的答案中提供对我一直在为这两种情况研究的解决方案的参考。

标签: java xpath xsd


【解决方案1】:

这是可以做到的,但您需要注意所有允许路径的集合是无限的(例如由于递归或由于通配符),因此您需要这个无限集合的智能表示,否则您的代码将如果您发现列表无法枚举,则需要放弃并返回“anything going”之类的内容。模式感知的 Saxon 产品在检查路径表达式(例如 .//para 与模式)时会做类似这样的事情:如果它知道上下文项的类型,它可以确定 .//para 是否能够选择任何东西,如果没有,给你一个警告。

作为第一步,您需要从源模式文档构建(相关部分)模式组件模型。不要试图自己做这件事,这是太多的工作。许多产品都有允许您访问模式组件模型的 API。 Saxon 允许您使用 Validate 命令行上的 -scmout 标志从源模式文档生成模式组件模型作为 XML 表示。

一旦你有了模式组件模型,你就可以找到一个元素的允许子元素,方法是转到它的复杂类型(如果它是一个简单类型,那么答案很简单)并递归地遍历粒子树,只寻找元素粒子和通配符粒子(你可能决定如果有通配符粒子最好放弃)。您可能不仅要考虑元素的声明类型,还要考虑从该元素扩展派生的其他类型。您需要知道允许的子元素的元素声明,而不仅仅是允许的子元素名称,因为当然要找到允许的孙子元素,您需要从元素声明开始,因为可能有元素的本地声明同名。

当然,当您知道元素名称与其允许的子元素之间的关系时,路径集就是该关系的传递闭包。

【讨论】:

  • 感谢您的回答 - 我在很大程度上将它用作我对这篇文章的回答中描述的实现的基础,它只依赖于 scala.xml (并且曾经是标准的一部分图书馆!)。仍然有一些粗糙的边缘,但随着使用和兴趣,希望它可以变得更普遍有用。
【解决方案2】:

我一直在研究project,它具有以下方法:1) 提取 xml 文档本身(例如模式定义文档)中存在的所有元素的 xpath,或 2) 列出所有可能找到的 xpath在 XSD 描述的 xml 文档中。

如果您只对 1) 问题和我的解决方案感兴趣,我的解决方案已在 Scala: What is the easiest way to get all leaf nodes and their paths in an XML? 得到描述和回答(尽管是在 Scala 中)

对于 2),事情要复杂得多,尽管实际上我使用 1) 作为起点,并且 1) (XpathXmlEnumerator) 和 2) (XpathXsdEnumerator) 共享一个通用接口 (XpathEnumerator ),不管它值多少钱。虽然 2) 更长,但我认为在 ~500 LOC 时它仍然是一个相当精简的实现,考虑到所有因素(但可能会使用更多的 cmets - 请让我添加它们!)。 @michael-kay 在描述许多困难并概述了可能的解决方案方面做得很好。也许不幸的是,我没有遵循他的建议来使用理解架构组件模型的软件,但我确实使用了scala.xml 来尝试简化一般使用 xml 节点的工作。尽管如此,我相信我克服了生成 xpath 的所有已知困难,因为在 XSD 中存在很高比例的信息/节点,为了在 XSD 描述的文档中生成 XPath,不需要理解这些信息/节点,所以一个可以简单地忽略这些节点。

过滤的想法变得很重要,以避免计算无处不在的节点,而您实际上并不真正关心,并且还可能避免递归。然而,递归应该被 2) 中的实现自动检测到,避免了对给定 xpath 的进一步遍历。对于过滤器,支持开始使用自定义 NodeFilters 类 - 参见 DdiCodebookSpec 示例用法。

您可以在与ShipOrderXsdSpec 相同的目录中看到在项目中运行的一些测试,如果您想尝试一下,其中包含一些快速运行的示例。其他一些测试没有快速运行,还有一些存在问题 - 这是“pre-alpha”软件!

虽然解决方案在 Scala 中,但我很乐意创建一个 Java 包装器(如果需要 - 它可以直接工作),如果有人真的想要它,甚至可以将它发布到 Maven。

【讨论】:

    【解决方案3】:
    Node n = doc.getFirstChild();
    NodeList nl = n.getChildNodes();
    

    然后可以尝试遍历节点列表,获取每个节点的XPath

    String getXPath(Node node)
    {
        Node parent = node.getParent();
        if (parent == null) {
            return "/" + node.getTagName();
        }
        return getXPath(parent) + "/";
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-27
      • 2019-07-20
      相关资源
      最近更新 更多