【问题标题】:XML: why is my DOM traversal function yielding only the top-level node?XML:为什么我的 DOM 遍历函数只产生顶级节点?
【发布时间】:2017-07-22 23:42:36
【问题描述】:

我想我会编写一个简单的函数来访问 DOM 树中的所有节点。我写了它,给了它一个不太复杂的 XML 来处理它,但是当我运行它时,我只得到了顶级 (DOMDocument) 节点。

请注意,我使用的是 PHP 的生成器语法: http://php.net/manual/en/language.generators.syntax.php

这是我的功能:

function DOMIterate($node)
{
    yield $node;
    if ($node->hasChildNodes())
    {
        foreach ($node->childNodes as $subnode) {
            // if($subnode != null) {
                DOMIterate($subnode);
            // }
        }
    }
}

以及应该打印结果的测试用例代码:

 $doc = new DOMDocument();
    $doc->loadXML($input);

    foreach (DOMIterate($doc) as $node) {
        $type = $node->nodeType;
        if ($type == XML_ELEMENT_NODE) {
            $tag = $node-> tagName;
            echo "$tag\n";
        }
        else if ($type == XML_DOCUMENT_NODE) {
            echo "document\n";
        }
        else if ($type == XML_TEXT_NODE) {
            $text = $node->wholeText;
            echo "text: $text\n";
        } else {
            $linenum = $node->getLineNo();
            echo "unknown node type: $type at input line $linenum\n";
        }
    }

输入的 XML 是前 18 行 https://www.w3schools.com/xml/plant_catalog.xml 加上一个结束

【问题讨论】:

  • 嗯...只是想到了一些东西。是否禁止“生成器”函数递归调用自身?如果是这样,是否有人有将遍历递归结构的“生成器”的示例?

标签: php xml recursion generator


【解决方案1】:

如果你使用的是 PHP7,你可以试试这个:

<?php

$string = <<<EOS
<div level="1">
    <div level="2">
        <p level="3"></p>
        <p level="3"></p>
    </div>
    <div level="2">
        <span level="3"></span>
    </div>
</div>
EOS;

$document = new DOMDocument();
$document->loadXML($string);

function DOMIterate($node)
{
    yield $node;
    if ($node->childNodes) {
        foreach ($node->childNodes as $childNode) {
            yield from DOMIterate($childNode);
        }
    }
}

foreach (DOMIterate($document) as $node) {
    echo $node->nodeName . PHP_EOL;
}

这是一个工作示例 - http://sandbox.onlinephpfunctions.com/code/ab4781870f8f988207da78b20093b00ea2e8023b 请记住,您还将获得标签中包含的文本节点。

【讨论】:

  • Barmar 和 motanelu 的(等效)答案在我尝试时有效。谢谢。
【解决方案2】:

在从生成器调用的函数中使用yield 不会将值返回给原始生成器的调用者。您需要使用yield from 将值传播回来。

function DOMIterate($node)
{
    yield $node;
    if ($node->hasChildNodes())
    {
        foreach ($node->childNodes as $subnode) {
            // if($subnode != null) {
                yield from DOMIterate($subnode);
            // }
        }
    }
}

这需要 PHP 7。如果您使用的是早期版本,请参阅 Recursive generators in PHP

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-25
    • 1970-01-01
    • 2016-10-22
    相关资源
    最近更新 更多