【问题标题】:How to get attributes from parents of an xml node efficiently如何有效地从 xml 节点的父节点获取属性
【发布时间】:2017-04-12 14:08:35
【问题描述】:

我正在使用 SimpleXML / XPath 编写一个 PHP 脚本,该脚本需要打印 XML 文件中句子的引用,该文件的结构类似于以下内容:

<text name="text_title">
  <book name="book_title">
    <chapter name="chapter_title">
      <sentence name="sentence_number" id="0000">
        <word attr="desired_val" id="1111" />
        <word attr="undesired_val" id="2222" />
      </sentence>
    </chapter>
  </book>
</text>

问题是我需要返回包含带有 attr="desired_val" 的单词的每个句子,然后是包含其文本、书籍、章节和句子编号的引文。我目前正在使用 xpath 查询进行第一部分

//word[@$attr='desired_val']/ancestor::sentence

第二部分基于每个返回句子的 ID 属性进行一系列后续 xpath 查询,例如对于文本节点:

/text/[book/chapter/sentence[@id={$id}]]/@name

(等等,对于其他相关节点)。我的问题是,如果有大量记录,这会变得非常低效,并导致脚本超时,结果超过十个。任何人都可以提出有关更好方法的想法吗?

【问题讨论】:

  • 你能分享想要的输出吗?你究竟想如何简化你的表达?你想摆脱book/chapter/sentence还是什么?
  • 我猜每个文本匹配的单词数量相当大。这导致文本元素的冗余结果。您真的对冗余结果列表感兴趣吗?如果不是,则在该文本元素中的第一个单词匹配之后停止在该文本元素中的搜索就足够了。
  • /text/[book/chapter/sentence[word[@id={$id}]]]/@name
  • 我应该指定一旦返回句子祖先,它的id值就绑定到$id。我将立即进行编辑以表示这一点,但第二个 XPath 查询对于我想要它执行的操作是正确的。 @ceving 关于大量匹配是正确的——不幸的是,这就是野兽的本性。我确实需要得到所有这些,而不是单身。例如,使用上面给出的结构,所需的输出或多或少类似于“1111 2222: text_title, Book book_title, Chapter chapter_title, sentence sentence_number”
  • 对于给定的节点来说,返回那个节点的每个祖先的“name”属性的值(假设它存在)似乎比它更容易,这是问题的根源。

标签: php xml xpath


【解决方案1】:

如果您需要所有匹配项,我能想到的唯一优化就是减少大量查询。构建整个匹配列表需要很多时间,以便在文档中寻找每个匹配以收集剩余信息。相反,最好只需一步即可从您的文档中查询必要的数据。同样的问题也发生在数据库应用程序中,人们执行了太多的 SQL 语句,而不是在一个查询中完成所有事情。

XML 的 SQL 称为 XQuery。如果您使用 XQuery 而不是 XPath,则只需一步即可收集所有必要的数据。以下示例已使用 Saxon-HE 作为 XQuery 引擎进行了测试。

<results>
{
  for $x in doc("text.xml")/text/book/chapter/sentence/word
  where $x/@attr = "desired_val"
  return <match text="{$x/../../../../@name}"
                book="{$x/../../../@name}"
                chapter="{$x/../../@name}"
                sentence="{$x/../@name}" />
}
</results>

以下命令

java -cp /usr/share/java/Saxon-HE.jar net.sf.saxon.Query '!indent=yes' text.xquery

只需一步即可从文档中提取所需信息。

<?xml version="1.0" encoding="UTF-8"?>
<results>
   <match chapter="chapter_title"
          text="text_title"
          book="book_title"
          sentence="sentence_number"/>
</results>

Saxon-HE 可以通过以下命令安装在 Ubuntu 上。

apt-get install libsaxonhe-java

我不知道哪个 XQuery 引擎最适合 PHP。

【讨论】:

  • 非常感谢您的提示——我昨晚对朋友说“我需要的是用于 XML 的 SQL”,所以这看起来很有希望。我会调查并报告任何结果。对于 PHP,这些看起来是城里的主要游戏:zorba、BaseX、Xquery Lite
  • 通过在服务器模式下安装和使用BaseX,我能够让一切都完全按照期望(并且非常快速)工作。以前服务器谋杀查询的替代方案在 338 毫秒左右返回。非常感谢@ceving 和大家的帮助。
猜你喜欢
  • 2022-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-10
  • 1970-01-01
相关资源
最近更新 更多