使用 PHP DOM 文档从 HTML 字符串获取菜单数组

Get menu array from HTML string using PHP DOM document

我有以下代码:

$string = '<html><head></head><body><ul id="mainmenu">
  <li id="1"><a href="1"> main menu 1 </a> </li>
  <li id="2"> <a href="2"> main menu 2 </a> </li>
    <ul class="sub-menu">
      <li id="3"> <a href="3"> Sub menu 2 </a> </li>
      <li id="4"> <a href="4"> Sub menu 2.1 </a> </li>
    </ul>
  </li>
</ul></body></html>';
$dom = new DOMDocument;
$dom->loadHTML($string);

现在我想要一个数组作为输出,其中包含使用 PHP DOM 文档的各自值的 href、值和子菜单字段。

像这样:

Array
(
    [0] => Array
        (
            [href] => 1
            [name] => Main menu 1
            [sub] => Array
                (
                )

        )

    [1] => Array
        (
            [href] => 2
            [name] => main menu 2
            [sub] => Array
                (
                   [0] => Array
                    (
                       [href] => 3
                       [name] => sub menu 2
                       [sub] => Array
                             (
                              )

                    )

                   [1] => Array
                       (
                         [href] => 4
                          [name] => sub main menu 2.1
                         [sub] => Array
                             (

                             )

                   )
                )

        )
)

我能够将所有菜单项作为主菜单,将所有子菜单数组设为空。如何通过解析 HTML 字符串来实现?

假设您只有两个级别,此代码使用 XPath 查找每个菜单的开头,然后循环遍历 <li> 元素。它对子菜单做类似的事情,使用当前主菜单作为起点并且仅使用内容(使用 descendant:: 来限制搜索的节点)......

(我不得不更改 HTML,因为 <li id="2"> <a href="2"> main menu 2 </a> </li> 中有一个额外的 <li>

$string = '<html><head></head><body><ul id="mainmenu">
  <li id="1"><a href="1"> main menu 1 </a> </li>
  <li id="2"> <a href="2"> main menu 2 </a>
    <ul class="sub-menu">
      <li id="3"> <a href="3"> Sub menu 2 </a> </li>
      <li id="4"> <a href="4"> Sub menu 2.1 </a> </li>
    </ul>
  </li>
</ul></body></html>';
$dom = new DOMDocument;
$dom->loadHTML($string);
$xp = new DOMXPath($dom);
$menus = [];

$mainMenus = $xp->query('//ul[@id="mainmenu"]/li');
foreach ( $mainMenus as $menu )  {
    $a = $menu->getElementsByTagName("a")[0];
    $newMenu = [ "href" => $a->getAttribute("href"),
        "name" => $a->textContent
    ];

    $subMenus = $xp->query('descendant::ul[@class="sub-menu"]/li', $menu);
    foreach ( $subMenus as $menu1 )  {
        $a = $menu1->getElementsByTagName("a")[0];

        $newMenu['sub'][] = [ "href" => $a->getAttribute("href"),
            "name" => $a->textContent
        ];
    }
    $menus[] = $newMenu;
}

如果您有一个可能的 ID 列表,那么您可以使用 XPath 找到其中任何一个..

//ul[@id="mainmenu" or @id="menu-main" or @id="menu-menu1"]/li

如果需要,您可以从数组动态构建它...

$menu_ids_arr = array('mainmenu', 'menu-main', 'menu-menu1');
$query = '//ul[';
foreach ( $menu_ids_arr as $id )    {
    $query .= '@id="'.$id.'" or ';
}
$query = substr($query, 0, -4).']/li';
$mainMenus = $xp->query($query);