使用PHP和XPath获取祖先节点

4

如果下面的内容有点混乱,请原谅,我一直在努力地解决这个问题。

这是一个XML块(从一个大型网站导出),我正在使用它来创建一个小型CMS的类别树。一旦我得到了节点的值和名称,这不是问题,我还需要获取每个节点的“父节点”,也就是在层次结构中位于其上方的节点。

    <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中使用ancestor、previous-sibling和parent等不同的查询方式,但仍然无法获得所需的节点。
这是我放弃几分钟前尝试的代码。
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表达式,可选择所需的名为“parent”的节点。 - Dimitre Novatchev
2个回答

2
您使用的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片段:
```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");

2
无法感谢你足够的empo,这正是我所需要的。现在脚本运行得非常完美! - PenguinOfwar
1
哇,这是我第一次尝试 PHP,结果不错。我之前了解过一些 XPath,这对我有所帮助。 - Emiliano Poggi

1

使用(假设初始上下文节点为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>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接