【问题标题】:Get ancestor node with PHP and xpath使用 PHP 和 xpath 获取祖先节点
【发布时间】:2011-11-10 18:16:43
【问题描述】:

如果以下内容有些混乱,请原谅,我一直在试图解决这个问题。

这是我用来为迷你 CMS 创建类别树的一段 XML(从一个非常大的站点导出)。一旦我得到了节点的值和名称,这没问题,我还需要获取每个节点的“父节点”,即在层次结构中位于它之前的节点。

    <productCategory>
    <genericName>DigitalCinema</genericName>
    <productCategories>
      <productCategory>
        <genericName>DCinemaProj</genericName>
        <productModels>
          <productModel>ProjProd-1</productModel>
          <productModel>ProjProd-2</productModel>
          <productModel>ProjProd-3</productModel>
          <productModel>ProjProd-4</productModel>
        </productModels>
      </productCategory>
      <productCategory>
        <genericName>DCinemaLens</genericName>
      </productCategory>
    </productCategories>
  </productCategory>

例如,对于 productCategory-genericName DCinemaLens,我需要能够将父级获取为 DigitalCinema,对于单个 productModel 个节点,其父节点是 DCinemaProj

我在 xpath 中使用祖先、上一个兄弟和父级尝试了各种不同的查询,但我仍然看不到抓取我需要的节点。

这是我几分钟前放弃尝试的代码。

if ($xml->xpath('//productCategories')) {

    foreach($xml->xpath('//genericName | //productModel') as $genericName){

    echo "<p align='center'>$genericName";

    $type = $genericName->getName();

    echo " - (" . $type . ") ";

    $derp = $xml->xpath("ancestor::productCategory[1]/genericName");

    echo $derp;

    echo '</p>';

    }

    }

我在数组中获取信息也取得了一些成功,但它总是再次返回 XML 中的每个值。

$key = 'genericName';

    $derpgleep = $derp[$key];

    echo 'Derp= ' . $derpgleep;

    print_r($derp);

希望我忽略了一个非常简单的解决方案。我希望我已经清楚了。

【问题讨论】:

  • 好问题,+1。请参阅我的答案,了解一个完整、简短且简单的 XPath 表达式,它选择所需的节点,称为“父节点”。

标签: php xml xpath simplexml


【解决方案1】:

您正在使用的 XPath 表达式:

 ancestor::productCategory[1]/genericName

如果您能够从当前节点开始执行该表达式,则将起作用。这确实不可能从当前的 Array $genericName 开始,因为它不包含父母,也不包含祖先。

我认为您的选择是重新遍历所有 XML 树。这是一个示例测试,可根据您的输入样本按要求工作。

<?php
$xml = simplexml_load_file("test_input1.xml");

if ($xml->xpath('//productCategories')) {

    foreach($xml->xpath('//genericName') as $genericName){

        echo "<p align='center'>$genericName";

        $type = $genericName->getName();

        echo " - (" . $type . ") ";

        $derp = $xml->xpath("//genericName[.='" . 
            $genericName[0] . 
            "']/ancestor::productCategory[2]/genericName");

        echo $derp[0];  echo "</p>\n";
    }
}
?>

这将打印出以下 HTML 片段:

<p align='center'>DigitalCinema - (genericName) </p>
<p align='center'>DCinemaProj - (genericName) DigitalCinema</p>
<p align='center'>DCinemaLens - (genericName) DigitalCinema</p>

虽然要获得 productModel 的“父级”,但您需要一个 xpath,例如:

        $derp = $xml->xpath("//productModel[.='" . 
            $productModel[0] . 
            "']/parent::productCategory[1]/genericName");

【讨论】:

  • empo 感激不尽,这正是我所需要的。该脚本现在可以完美运行!
  • 哇,这是一个很好的结果,因为这是我第一次尝试 php。我知道一点 XPath,这对我很有帮助。
【解决方案2】:

使用(假设初始上下文节点是productCategory[genericName = 'DCinemaLens']productModel):

../preceding-sibling::*[1]

基于 XSLT 的验证

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/">
  <xsl:copy-of select=
  "/*/*/productCategory
            [genericName = 'DCinemaLens']
               /../preceding-sibling::*[1]"/>
-------------
<xsl:text/>
  <xsl:copy-of select=
  "/*/*/*/*/productModel/../preceding-sibling::*[1]"/>
 </xsl:template>
</xsl:stylesheet>

当此转换应用于提供的 XML 文档时

<productCategory>
    <genericName>DigitalCinema</genericName>
    <productCategories>
        <productCategory>
            <genericName>DCinemaProj</genericName>
            <productModels>
                <productModel>ProjProd-1</productModel>
                <productModel>ProjProd-2</productModel>
                <productModel>ProjProd-3</productModel>
                <productModel>ProjProd-4</productModel>
            </productModels>
        </productCategory>
        <productCategory>
            <genericName>DCinemaLens</genericName>
        </productCategory>
    </productCategories>
</productCategory>

需要的两个元素被复制到输出中

<genericName>DigitalCinema</genericName>
-------------
<genericName>DCinemaProj</genericName>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-09
    • 1970-01-01
    • 2011-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多