Çok boyutlu dizi yineleme

1 Cevap php

Eğer şu diziyi söylüyorlar:

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

Bunu nasıl gibi görünüyor böylece bir XML dizesi dönüştürerek hakkında gitmek istiyorum:

<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>

Bunu yapmanın tek yolu gibi bir özyinelemeli yöntemi ile olacaktır:

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

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

    echo "</node>";
}

traverse($nodes);

Gerçi, yineleme kullanan bir yaklaşım arıyorum.

1 Cevap

Sen Iterator dizi üzerinden yineleme ve sonra istediğiniz çıktıyı üretmek için kullanabilirsiniz:

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);
    }
}

ve sonra bu gibi monte:

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

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

çıkışlar

<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>

Boş dışarı $key kullanırken $key => $val, bunu ekleyin TraverseArrayIterator

public function key()
{ 
    return '';
}

Amacınız XML üretmek gibi görünüyor bu yana, aynı zamanda Iterasyon için bir işbirlikçisi olarak bir yazar XMLWriter geçebileceği. Bu oluşturulan XML üzerinde daha fazla kontrol sağlar ve aynı zamanda çıkış geçerli XML emin kılar:

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());
    }
}

Daha sonra bu gibi kullanmak istiyorum:

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

ve foreach 'o zaman aynı çıktıyı üretecek üzerinde ing (ancak XML prolog ekleme)