0

配列の変換について助けが必要です。次のようなフラット配列があります。

Array
(
[0] =>  av_one_third
[1] =>  av_icon_box
[2] =>  /av_icon_box
[3] =>  av_button
[4] =>  av_icon_box
[5] =>  /av_icon_box
[6] =>  /av_one_third

)

この配列の値は、実際には xml のような構造からのタグです。今必要なのは、この配列を、次の構造に似たネストされた配列に変換することです。

[0] => Array
    (
        [tag] => av_one_third
        [content] => Array
            (
                [1] => Array
                    (
                        [tag] => av_icon_box
                        [content] => Array
                            (
                            )

                    )

                [2] => Array
                    (
                        [tag] => av_button
                        [content] => Array
                            (
                            )

                    )  

                [3] => Array
                    (
                        [tag] => av_icon_box
                        [content] => Array
                            (
                            )

                    )


            )

    )
etc

これを行う簡単な方法はありますか?私の最初のアイデアは、配列を xml 文字列に変換し、phps ネイティブ XML 関数の 1 つを使用することでしたが、問題は、自己終了タグがそのようにラベル付けされていないことです。上記の場合、av_button タグには、私が試した xml 解析関数の終了タグ スローがありません。

いくつかの追加要件: - 要素は任意の数の子を保持できます - 最終的な配列は正しい順序を維持する必要があります

これを簡単に解決できるスマート配列ソート関数はありますか? これに関するヒントをいただければ幸いです。

よろしくお願いします :)

4

1 に答える 1

1

配列には、階層をエンコードする典型的なフラット構造があります。ただし、そこでエラーを修正した場合に限ります。

基本的には、次のリストのようにPHPコードで機能します。これには、データのどこにエラーがあるかを示す例外が含まれ、データを修正できます(このウェブサイトで同様の例を見つけることができます。たとえば、シリーズの変換方法のリンクされた質問を参照してください。親子関係を階層ツリーに変換しますか?):

  1. ツリー配列内のルートエントリを初期化します。そこで子供を追加できます。

    $tree     = ['children' => []];
    
  2. 最初の要素(レベル0)がツリーのルート要素を指すポインターの配列をツリーに作成します。

    $pointers = [&$tree];
    
  3. 次に、データ内の各行に目を通します。

    foreach ($data as $index => $line) {
    
  4. ラインが閉じるかどうかを決定し、その決定結果を保存します。

    $close = '/' === $line[0];
    
  5. ポインタの現在の数を保存します。

    $count = count($pointers);
    
  6. 行が閉じない場合は、新しい要素を開いて続行します。

    $pointers[$count]                   = ['tag' => $line, 'children' => []];
    $pointers[$count - 1]['children'][] = & $pointers[$count];
    continue;
    
  7. 代わりに行が閉じる場合は、タグ名が一致するかどうかを検証し、一致する場合は、最後に作成されたポインターを削除します。

    if ($count === 1) {
        throw new RuntimeException('Can not close on lowest level.');
    }
    
    $name = $pointers[$count - 1]['tag'];
    
    if ($name !== substr($line, 1)) {
        throw new RuntimeException(
            "Invalid closing element <$line> (line #$index) in <$name>"
        );
    }
    
    array_pop($pointers);
    
  8. すべての行がアウトラインのように処理された後、すべてのポインターを削除できます。

    unset($pointers);
    
  9. 結果は、ルートノードの最初の子にある配列です。変数に割り当てることができ、不要な参照を削除できます。

    $result = &$tree['children'][0];
    unset($tree);
    print_r($result);
    

データが正しい場合は、次の出力例が表示されます。

Array
(
    [tag] => av_one_third
    [children] => Array
        (
            [0] => Array
                (
                    [tag] => av_icon_box
                    [children] => Array
                        (
                        )
                )
            [1] => Array
                (
                    [tag] => av_button
                    [children] => Array
                        (
                        )
                )
            [2] => Array
                (
                    [tag] => av_icon_box
                    [children] => Array
                        (
                        )
                )
        )
)
于 2013-03-03T21:27:12.063 に答える