1

古い HTML サイトを新しい CMS に変換しようとしています。正しいメニュー階層 (さまざまな深さ) を取得するには、PHP ですべてのファイルを読み取り、メニュー (ネストされた順序付けられていないリスト) を連想配列に抽出/解析します。

root.html
<ul id="menu">
  <li class="active">Start</li>
  <ul>
    <li><a href="file1.html">Sub1</a></li>
    <li><a href="file2.html">Sub2</a></li>
  </ul>
</ul>

file1.html
<ul id="menu">
  <li><a href="root.html">Start</a></li>
  <ul>
    <li class="active">Sub1</li>
    <ul>
      <li><a href="file3.html">SubSub1</a></li>
      <li><a href="file4.html">SubSub2</a></li>
      <li><a href="file5.html">SubSub3</a></li>
      <li><a href="file6.html">SubSub4</a></li>
    </ul>
  </ul>
</ul>

file3.html
<ul id="menu">
  <li><a href="root.html">Start</a></li>
  <ul>
    <li><a href="file1.html">Sub1</a></li>
    <ul>
      <li class="active">SubSub1</li>
      <ul>
        <li><a href="file7.html">SubSubSub1</a></li>
        <li><a href="file8.html">SubSubSub2</a></li>
        <li><a href="file9.html">SubSubSub3</a></li>
      </ul>
    </ul>
  </ul>
</ul>

file4.html
<ul id="menu">
  <li><a href="root.html">Start</a></li>
  <ul>
    <li><a href="file1.html">Sub1</a></li>
    <ul>
      <li><a href="file3.html">SubSub1</a></li>
      <li class="active">SubSub2</li>
      <li><a href="file5.html">SubSub3</a></li>
      <li><a href="file6.html">SubSub4</a></li>
    </ul>
  </ul>
</ul>

すべてのファイルをループして、「id="menu"」を抽出し、階層とファイル情報を維持しながら、このような (または同様の) 配列を作成したいと思います

Array 
  [file] => root.html
  [child] => Array 
    [Sub1] => Array 
      [file] => file1.html
      [child] => Array  
        [SubSub1] => Array 
          [file] => file3.html
          [child] => Array 
            [SubSubSub1] => Array 
              [file] => file7.html
            [SubSubSub2] => Array 
              [file] => file8.html                      
            [SubSubSub3] => Array
              [file] => file9.html
        [SubSub2] => Array
          [file] => file4.html
        [SubSub3] => Array 
          [file] => file5.html
        [SubSub4] => Array 
          [file] => file6.html
    [Sub2] => Array
      [file] => file2.html 

PHP Simple HTML DOM Parser librayの助けを借りて、ファイルを正常に読み取り、メニューを抽出しました

$html = file_get_html($file);
foreach ($html->find("ul[id=menu]") as $ul) {
  ..
}

メニューのアクティブなセクションのみを解析するには (1 つ以上のレベルアップへのリンクを除外します)、使用しました

$ul->find("ul",-1)

これは、外側の ul 内の最後の ul を見つけます。これは、単一のファイルに最適です。

しかし、各メニューの深さが異なるため、すべてのファイル/メニューをループして親/子情報を保持するのに問題があります。

すべての提案、ヒント、ヘルプに感謝します!

4

2 に答える 2

0

これは、上向きのリンクを持つディレクトリ ツリーに似ています。レベル 1 の file1 はレベル 2 の file3 を指し、これはレベル 1 のファイル 1 を指しており、これが「異なる深さ」を引き起こします。文字列の配列の配列ではなく、上向きと下向きの特定のメニューオブジェクトを設定し、そのリストを保持することを検討してください。このような php の階層の出発点は、次のようなクラスになります。

class menuItem {

    protected $leftSibling = null;
    protected $rightSibling = null;

    protected $parents = array();
    protected $childs = array();

    protected properties = array();

    // set property like menu name or file name
    function setProp($name, $val) {
        $this->properties[$name] = $val;
    }

    // get a propertue if set, false  otherwise
    function getProp($name) {
        if ( isset($this->properties[$name]) )
            return $this->properties[$name];
        return false;
    }

    function getLeftSiblingsAsArray() {
        $sibling = $this->getLeftSibling();
        $siblings = array();
        while ( $sibling != null ) {
            $siblings[] = $sibling;
            $sibling = $sibling->getLeftSibling();
        }
        return $siblings;
    }

    function addChild($item) {
        $this->childs[] = $item;
    }

    function addLeftSibling($item) {
        $sibling = $this->leftSibling;
        while ( $sibling != null ) {
            if ( $sibling->hasLeft() )
                $sibling = $sibling->getLeftSibling();
            else {
                $sibling->addFinalLeft($item);
                break;
            }
        }
    }

    function addFinalLeft(item) {
        $sibling->leftSibling = $item;
    }

    ....
于 2014-01-23T13:33:03.590 に答える
0

編集:OK、これは結局それほど簡単ではありませんでした:)

ところで、このライブラリは本当に優れたツールです。それを書いた人たちへの称賛。

考えられる解決策の 1 つを次に示します。

class menu_parse {

    static $missing = array(); // list of missing files

    static private $files = array(); // list of source files to process

    // initiate menu parsing
    static function start ($file)
    {
        // start with root file
        self::$files[$file] = 1;

        // parse all source files
        for ($res=array(); current(self::$files); next(self::$files))
        {
            // get next file name
            $file = key(self::$files);

            // parse the file
            if (!file_exists ($file))
            {
                self::$missing[$file] = 1;
                continue;
            }
            $html = file_get_html ($file);

            // get menu root (if any)
            $root = $html->find("ul[id=menu]",0);
            if ($root) self::menu ($root, $res);
        }

        // reorder missing files array
        self::$missing = array_keys (self::$missing);

        // that's all folks
        return $res;
    }

    // parse a menu at a given level
    static private function menu ($menu, &$res)
    {
        foreach ($menu->children as $elem)
        {
            switch ($elem->tag)
            {
            case "li" : // name and possibly source file of a menu

                // grab menu name
                $name = $elem->plaintext;

                // see if we can find a link to the menu file
                $link = $elem->children(0);
                if ($link && $link->tag == 'a')
                {
                    // found the link
                    $file = $link->href;
                    $res[$name]->file = $file;

                    // add the source file to the processing list
                    self::$files[$file] = 1;
                }
                break;

            case "ul" : // go down one level to grab items of the current menu
                self::menu ($elem, $res[$name]->childs);
            }   
        }
    }
}

使用法:

// The result will be an array of menus indexed by item names.
//
// Each menu will be an object with 2 members
// - file   -> source file of the menu
// - childs -> array of menu subtitems
//
$res = menu_parse::start ("root.html");

// parse_menu::$missing will contain all the missing files names

echo "Result : <pre>";
print_r ($res);
echo "</pre><br>missing files:<pre>";
print_r (menu_parse::$missing);
echo "</pre>";

テスト ケースの出力:

Array
(
  [Start] => stdClass Object
    (
      [childs] => Array
        (
          [Sub1] => stdClass Object
            (
              [file] => file1.html
              [childs] => Array
                (
                  [SubSub1] => stdClass Object
                    (
                      [file] => file3.html
                      [childs] => Array
                        (
                          [SubSubSub1] => stdClass Object
                            (
                              [file] => file7.html
                            )
                          [SubSubSub2] => stdClass Object
                            (
                              [file] => file8.html
                            )
                          [SubSubSub3] => stdClass Object
                            (
                              [file] => file9.html
                            )
                        )
                    )
                  [SubSub2] => stdClass Object
                    (
                      [file] => file3.html
                    )
                  [SubSub3] => stdClass Object
                    (
                      [file] => file5.html
                    )
                  [SubSub4] => stdClass Object
                    (
                      [file] => file6.html
                    )
                )
            )
          [Sub2] => stdClass Object
            (
              [file] => file2.html
            )
        )
      [file] => root.html
    )
)

missing files: Array
(
    [0] => file2.html
    [1] => file5.html
    [2] => file6.html
    [3] => file7.html
    [4] => file8.html
    [5] => file9.html
)

ノート:

  • コードは、すべてのアイテム名が特定のメニュー内で一意であることを前提としています。

コードを変更して、(サブ) メニューを配列として数値インデックスと名前をプロパティとして持つことができます (同じ名前の 2 つの項目が互いに上書きされないようにするため) が、結果の構造が複雑になります。

このような名前の重複が発生した場合、最善の解決策は、項目の 1 つ、IMHO の名前を変更することです。

  • このコードは、ルート メニューが 1 つしかないことも前提としています。

複数を処理するように変更することはできますが、それはあまり意味がありません (ルート メニュー ID の重複を意味し、最初にそれを処理しようとする JavaScript に問題を引き起こす可能性があります)。

于 2014-01-23T12:41:48.757 に答える