多维数组迭代

发布于 2024-08-20 05:21:20 字数 1057 浏览 4 评论 0原文

假设您有以下数组:

$nodes = array(
    "parent node",
    "parent node",
    array(
        "child node",
        "child node",
        array(
            "grand child node",
            "grand child node")));

您将如何将其转换为 XML 字符串,使其看起来像:

<node>
    <node>parent node</node>
    <node>parent node</node>
    <node>
        <node>child node</node>
        <node>child node</node>
        <node>
            <node>grand child node</node>
            <node>grand child node</node>
        </node>
    </node>
</node>

一种方法是通过递归方法,例如:

function traverse($nodes)
{
    echo "<node>";

    foreach($nodes as $node)
    {
        if(is_array($node))
        {
            traverse($node);
        }
        else
        {
            echo "<node>$node</node>";
        }
    }

    echo "</node>";
}

traverse($nodes);

不过,我正在寻找一种使用迭代的方法。

Say you have the following array:

$nodes = array(
    "parent node",
    "parent node",
    array(
        "child node",
        "child node",
        array(
            "grand child node",
            "grand child node")));

How would you go about transforming it to an XML string so that it looks like:

<node>
    <node>parent node</node>
    <node>parent node</node>
    <node>
        <node>child node</node>
        <node>child node</node>
        <node>
            <node>grand child node</node>
            <node>grand child node</node>
        </node>
    </node>
</node>

One way to do it would be through a recursive method like:

function traverse($nodes)
{
    echo "<node>";

    foreach($nodes as $node)
    {
        if(is_array($node))
        {
            traverse($node);
        }
        else
        {
            echo "<node>$node</node>";
        }
    }

    echo "</node>";
}

traverse($nodes);

I'm looking for an approach that uses iteration, though.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

紫竹語嫣☆ 2024-08-27 05:21:20

您可以使用 迭代器 迭代数组,然后生成您想要的输出:

class TranformArrayIterator extends RecursiveIteratorIterator
{
    protected function indent()
    {
        echo str_repeat("\t", $this->getDepth());
        return $this;
    }
    public function beginIteration()
    {
        echo '<nodes>', PHP_EOL;
    }
    public function endIteration()
    {
        echo '</nodes>', PHP_EOL;
    }
    public function beginChildren()
    {
        $this->indent()->beginIteration();
    }
    public function endChildren()
    {
        $this->indent()->endIteration();
    }
    public function current()
    {
        return sprintf('%s<node>%s</node>%s',
                       str_repeat("\t", $this->getDepth() +1),
                       parent::current(),
                       PHP_EOL);
    }
}

然后像这样组装它:

$iterator = new TranformArrayIterator(new RecursiveArrayIterator($nodes));

foreach($iterator as $val) {
    echo $val;
}

输出

<nodes>
        <node>parent node</node>
        <node>parent node</node>
        <nodes>
                <node>child node</node>
                <node>child node</node>
                <nodes>
                        <node>grand child node</node>
                        <node>grand child node</node>
                </nodes>
        </nodes>
</nodes>

使用 $key => 时清空 $key $val,将其添加到 TraverseArrayIterator

public function key()
{ 
    return '';
}

由于您的目标似乎是生成 XML,因此您还可以将 XMLWriter 作为协作者传递给 Iterator。这允许对生成的 XML 进行更多控制,并确保输出是有效的 XML:

class TranformArrayIterator extends RecursiveIteratorIterator
{
    private $xmlWriter;

    public function __construct(
        XmlWriter $xmlWriter, 
        Traversable $iterator, 
        $mode = RecursiveIteratorIterator::LEAVES_ONLY , 
        $flags = 0)
    {
        $this->xmlWriter = $xmlWriter;
        parent::__construct($iterator, $mode, $flags);
    }

    public function beginIteration()
    {
        $this->xmlWriter->startDocument('1.0', 'utf-8');
        $this->beginChildren();
    }
    public function endIteration()
    {
        $this->xmlWriter->endDocument();
    }
    public function beginChildren()
    {
        $this->xmlWriter->startElement('nodes');
    }
    public function endChildren()
    {
        $this->xmlWriter->endElement();
    }
    public function current()
    {
        $this->xmlWriter->writeElement('node', parent::current());
    }
}

然后您可以像这样使用它:

$xmlWriter = new XmlWriter;
$xmlWriter->openUri('php://output');
$xmlWriter->setIndent(true);
$xmlWriter->setIndentString("\t");
$iterator = new TranformArrayIterator(
    $xmlWriter,
    new RecursiveArrayIterator($nodes)
);

然后对其进行 foreach 将产生相同的输出(但添加XML 序言)

You could use an Iterator to iterate over the array and then produce your desired output:

class TranformArrayIterator extends RecursiveIteratorIterator
{
    protected function indent()
    {
        echo str_repeat("\t", $this->getDepth());
        return $this;
    }
    public function beginIteration()
    {
        echo '<nodes>', PHP_EOL;
    }
    public function endIteration()
    {
        echo '</nodes>', PHP_EOL;
    }
    public function beginChildren()
    {
        $this->indent()->beginIteration();
    }
    public function endChildren()
    {
        $this->indent()->endIteration();
    }
    public function current()
    {
        return sprintf('%s<node>%s</node>%s',
                       str_repeat("\t", $this->getDepth() +1),
                       parent::current(),
                       PHP_EOL);
    }
}

and then assemble it like this:

$iterator = new TranformArrayIterator(new RecursiveArrayIterator($nodes));

foreach($iterator as $val) {
    echo $val;
}

outputs

<nodes>
        <node>parent node</node>
        <node>parent node</node>
        <nodes>
                <node>child node</node>
                <node>child node</node>
                <nodes>
                        <node>grand child node</node>
                        <node>grand child node</node>
                </nodes>
        </nodes>
</nodes>

To blank out $key when using $key => $val, add this to TraverseArrayIterator

public function key()
{ 
    return '';
}

Since your aim seems to be to produce XML, you could also pass an XMLWriter as a collaborator to the Iterator. This allows for more control over the generated XML and also makes sure the output is valid XML:

class TranformArrayIterator extends RecursiveIteratorIterator
{
    private $xmlWriter;

    public function __construct(
        XmlWriter $xmlWriter, 
        Traversable $iterator, 
        $mode = RecursiveIteratorIterator::LEAVES_ONLY , 
        $flags = 0)
    {
        $this->xmlWriter = $xmlWriter;
        parent::__construct($iterator, $mode, $flags);
    }

    public function beginIteration()
    {
        $this->xmlWriter->startDocument('1.0', 'utf-8');
        $this->beginChildren();
    }
    public function endIteration()
    {
        $this->xmlWriter->endDocument();
    }
    public function beginChildren()
    {
        $this->xmlWriter->startElement('nodes');
    }
    public function endChildren()
    {
        $this->xmlWriter->endElement();
    }
    public function current()
    {
        $this->xmlWriter->writeElement('node', parent::current());
    }
}

You'd then use it like this:

$xmlWriter = new XmlWriter;
$xmlWriter->openUri('php://output');
$xmlWriter->setIndent(true);
$xmlWriter->setIndentString("\t");
$iterator = new TranformArrayIterator(
    $xmlWriter,
    new RecursiveArrayIterator($nodes)
);

and foreach'ing over it will produce the same output then (but adding the XML prolog)

空袭的梦i 2024-08-27 05:21:20
<?php

$nodes = array(
    "parent node",
    "parent node",
    array(
        "child node",
        "child node",
        array(
            "grand child node",
            "grand child node"
        )
    )
);

$s = '<node>';
$arr = $nodes;

while(count($arr) > 0)
{
    $n = array_shift($arr);
    if(is_array($n))
    {
        array_unshift($arr, null);
        $arr = array_merge($n, $arr);
        $s .= '<node>';
    }
    elseif(is_null($n))
        $s .= '</node>';
    else
        $s .= '<node>'.$n.'</node>';
}
$s .= '</node>';

echo $s;

?>
<?php

$nodes = array(
    "parent node",
    "parent node",
    array(
        "child node",
        "child node",
        array(
            "grand child node",
            "grand child node"
        )
    )
);

$s = '<node>';
$arr = $nodes;

while(count($arr) > 0)
{
    $n = array_shift($arr);
    if(is_array($n))
    {
        array_unshift($arr, null);
        $arr = array_merge($n, $arr);
        $s .= '<node>';
    }
    elseif(is_null($n))
        $s .= '</node>';
    else
        $s .= '<node>'.$n.'</node>';
}
$s .= '</node>';

echo $s;

?>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文