PHP DOM如何从UL获取项目和子项目

我正在尝试通过以下菜单获取所有带有锚标签的项目和子项目:

<nav class="header-nav" id="headerLara">
	<div class="menu-hauptmenu-container">
		<ul id="head_nav_ul" class="menu">
			<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-4">
				<a>First Menu</a>
				<ul class="sub-menu">
					<li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-14002">
						<a href="http://example.com/fm1">F menu 1</a>
					</li>
					<li class="menu-item menu-item-type-post_type menu-item-object-post menu-item-12718">
						<a href="http://example.com/fm2">F menu 2</a>
					</li>
				</ul>
			</li>
			<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-6">
				<a>Second Menu</a>
				<ul class="sub-menu">
					<li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-1257">
						<a href="http://example.com/sm1">S menu 1</a>
					</li>
					<li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-5420">
						<a href="http://example.com/sm2">S menu 2</a>
					</li>
				</ul>
			</li>
			<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-12821">
				<a href="http://example.com/m3">Third Menu</a>
			</li>
		</ul>
	</div>
</nav>

现在我想要像这样的输出:

<nav class="header-nav" id="headerLara">
	<div class="menu-hauptmenu-container">
		<ul>
			<li>
				<a class="has-child">First Menu</a>
				<ul>
					<li>
						<a href="http://example.com/fm1">F menu 1</a>
					</li>
					<li>
						<a href="http://example.com/fm2">F menu 2</a>
					</li>
				</ul>
			</li>
			<li>
				<a class="has-child">Second Menu</a>
				<ul>
					<li>
						<a href="http://example.com/sm1">S menu 1</a>
					</li>
					<li>
						<a href="http://example.com/sm2">S menu 2</a>
					</li>
				</ul>
			</li>
			<li>
				<a href="http://example.com/m3">Third Menu</a>
			</li>
		</ul>
	</div>
</nav>

我已经进行了一些研发,并尝试使用以下PHP代码:

    <?php
$doc = new DomDocument;
$doc->validateonParse = true;
$doc->loadHtml(file_get_contents('http://example.com/blabla.php'));
$header = $doc->getElementById('headerLara');

$mainUls = $header->getElementsByTagName('ul');
foreach ($mainUls as $mainUl) {
    echo '<ul>';
    $mainLis = $mainUl->getElementsByTagName('li');
    foreach ($mainLis as $mainLi) {
    echo '<li>';
    $mainAnc = $mainLi->getElementsByTagName('a');
    $href = $mainAnc->item(0)->getattribute('href');
    echo '<a class="has-child" href="'.$href.'">'.$mainAnc->item(0)->nodeValue.'</a>';   
    $secUls = $mainLi->getElementsByTagName('ul');
    if($secUls->length < 2){
        foreach ($secUls as $secUl) {
            echo '<ul>';
            $seclis = $secUl->getElementsByTagName('li');
            foreach ($seclis as $secli) {
                echo '<li>';
                $secAnc = $mainLi->getElementsByTagName('a');
                $shref = $secAnc->item(0)->getattribute('href');
                echo '<a href="'.$shref.'">'.$secAnc->item(0)->nodeValue.'</a>';  
                echo '</li>';
            }
            echo '</ul>';
        }
    }
    echo '</li>';
    }
    echo '</ul>';
}
?> 

但这对我不起作用,并返回如下输出:

<ul>
	<li>
		<a class="has-child" href="">First Menu</a>
		<ul>
			<li>
				<a href="">First Menu</a>
			</li>
			<li>
				<a href="">First Menu</a>
			</li>
		</ul>
	</li>
	<li>
		<a class="has-child" href="http://example.com/fm1">F menu 1</a>
	</li>
	<li>
		<a class="has-child" href="http://example.com/fm2">F menu 2</a>
	</li>
	<li>
		<a class="has-child" href="">Second Menu</a>
		<ul>
			<li>
				<a href="">Second Menu</a>
			</li>
			<li>
				<a href="">Second Menu</a>
			</li>
		</ul>
	</li>
	<li>
		<a class="has-child" href="http://example.com/sm1">S menu 1</a>
	</li>
	<li>
		<a class="has-child" href="http://example.com/sm2">S menu 2</a>
	</li>
</ul>

我检查了许多链接,这些链接似乎与我的问题相似,但没有任何帮助。

我如何获得正确的输出,请先谢谢。

dunhuangheisha 回答:PHP DOM如何从UL获取项目和子项目

有一些小错误(从错误的节点中拾取),但是有两个主要问题。

第一个是getElementsByTagName()选择具有该标签名称的 all 个子元素,这不仅限于直接的子节点,因此每次标签的数量都超出您的预期。在此代码中,它使用XPath,因为DOMDocument没有方便的方法来完成仅称为子节点的操作,因此XPath仅将上下文节点用作起点和类似a这样的话,只说<a>个标记是上下文节点的直接后代。

另一个(主要问题)是您正在使用echo语句构建输出。可能有效,但也容易出现错别字,无效的结构等。此代码使用DOM API调用来创建文档。

$doc = new DomDocument;
$doc->validateOnParse = true;
$doc->loadHtml($html);
$xp = new DOMXPath($doc);

$header = $doc->getElementById('headerLara');
$mainUls = $xp->query('div/ul',$header);
foreach ($mainUls as $mainUl) {
    $mainULE = $doc->createElement("ul");
    $mainLis = $xp->query('li',$mainUl);
    foreach ($mainLis as $mainLi) {
        $li = $doc->createElement("li");
        $mainAnc = $xp->query('a',$mainLi)[0];

        $href = $mainAnc->getAttribute('href');
        $a = $doc->createElement("a",htmlspecialchars($mainAnc->nodeValue));
        $href = $mainAnc->getAttribute('href');
        if ( !empty($href) )    {
            $a->setAttribute("href",$href);
        }
        $li->appendChild($a);
        $secUls = $xp->query('ul',$mainLi);
        if($secUls->length < 2){
            foreach ($secUls as $secUl) {
                $a->setAttribute("class","has-child");
                $secULE = $doc->createElement("ul");
                $secLis = $xp->query('li',$secUl);
                foreach ($secLis as $secLi) {
                    $secLIE = $doc->createElement("li");
                    $secAnc = $xp->query('a',$secLi);
                    $shref = $secAnc[0]->getAttribute('href');
                    $secA = $doc->createElement("a",htmlspecialchars($secAnc[0]->nodeValue));
                    $secA->setAttribute("href",$shref);
                    $secLIE->appendChild($secA);
                    $secULE->appendChild($secLIE);
                }
                $li->appendChild($secULE);
            }
        }
        $mainULE->appendChild($li);
    }
    echo PHP_EOL.PHP_EOL.">>>>".$doc->saveHTML($mainULE);
    // Next line replaces existing HTML
    //$mainUl->parentNode->replaceChild($mainULE,$mainUl);
}
本文链接:https://www.f2er.com/3154051.html

大家都在问