使用php xPath更改以前的兄弟值

时间:2015-10-16 13:14:16

标签: php xml xpath

我的情况让我发疯。我想在我的feed中搜索具有特定值的元素(从数组派生),如果找到该值,则更改它的前一个兄弟元素的值。

我的Feed看起来像这样

<products>
    <product>
        <properties>
            <property name="category">
                <value>Fruits</value>
            </property>
            <property name="item">
                <value>Banana</value>
            </property>
        </properties>
    </product>
    <product>
        <properties>
            <property name="category">
                <value>Fruits</value>
            </property>
            <property name="item">
                <value>Apple</value>
            </property>
        </properties>
    </product>
    <product>
        <properties>
            <property name="category">
                <value>Fruits</value>
            </property>
            <property name="item">
                <value>Carrot</value>
            </property>
        </properties>
    </product>
</products>

如您所见,Feed中可能存在一些错误。对于这些实例,我创建了一个具有适当值的数组,如下所示:

$replacements = Array(
    "Carrot" => "Vegetable"
);

现在,我想要选择具有property键值的属性item的每个$replacements,然后选择属性为{{1}的上一个兄弟元素并使用匹配的category值更改此值。

我想出了这个,但这只给了我一个没有输出的白色屏幕

$replacements

但我不明白为什么它不输出任何东西

3 个答案:

答案 0 :(得分:2)

这里有一些事情:

array_key_exists($entry->nodeValue,$replacements)

nodeValue将包含property元素及其后代中的所有文本内容 - 包括换行符和空格。

... = $replacements[$entries->nodeValue];

你可能正在寻找$replacements[$entry->nodeValue]但是你再次遇到与空白相同的问题。不仅如此,你还要用文本替换整个先前属性的nodeValue:

<property name="category">
    <value>Fruits</value>
</property>

将成为:

<property name="category">Vegetable</property>

要解决这个问题,我建议您调整查询,以及如何解决要替换的目标值,以便摆脱->previousSibling->previousSibling链接并更加明确。< / p>

实施例

foreach ($xpath->query('//property[@name="item"]/value') as $node) {
    if (array_key_exists(trim($node->textContent), $replacements)) {

        $target = $xpath->query(
            'preceding-sibling::property/value/text()',
            $node->parentNode
        )->item(0);

        $target->parentNode->replaceChild(
            $dom->createTextNode($replacements[trim($node->textContent)]),
            $target
        );

    }
}

echo $dom->saveXML();

输出:

    ...
    <product>
        <properties>
            <property name="category">
                <value>Vegetable</value>
            </property>
            <property name="item">
                <value>Carrot</value>
            </property>
        </properties>
    </product>
</products>

答案 1 :(得分:1)

您需要返回,为了做到这一点,您需要更正您的查询

$query = '//property[@name = "item"]/value';

答案 2 :(得分:0)

您可以尝试使用完整路径,所以:

$query = '//products/product/properties/property[@name = "item"]/value';
$entries = $xpath->query($query);

foreach ($entries as $entry) {
    if(array_key_exists($entry->nodeValue,$replacements)){
        $entry->previousSibling->previousSibling->nodeValue = $replacements[$entries->nodeValue];
    }
}

此外,您可以尝试使用contextManual):

$context = $document->getElementsByTagName('products')->item(0);
$query = './/property[@name = "item"]/value';//add a '.' before the query to make it relative to the context
$entries = $xpath->query($query, $context);

foreach ($entries as $entry) {
    if(array_key_exists($entry->nodeValue,$replacements)){
        $entry->previousSibling->previousSibling->nodeValue = $replacements[$entries->nodeValue];
    }
}

在非常相似的情况下,这两种解决方案都适用于我。