PHP DOM Как получить элементы и подпункты из UL - PullRequest
0 голосов
/ 06 ноября 2019

Я пытаюсь получить все элементы и подпункты с тегом привязки из следующего меню:

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

Я проверил много ссылок, похожих на мою проблему, но не нашел ничего полезного.

Как я могу получить правильный вывод, спасибо заранее.

1 Ответ

1 голос
/ 06 ноября 2019

Есть несколько незначительных ошибок (получение из неправильного узла), но есть две основные проблемы.

Первая - getElementsByTagName(), выбирающая все дочерние элементы с этим именем тега. это не ограничивается непосредственными дочерними узлами, поэтому каждый раз будет больше тегов, чем вы ожидаете. В этом коде он использует XPath, поскольку DOMDocument не имеет удобного способа сделать просто непосредственными дочерними узлами, называемыми , поэтому XPath просто использует узел контекста в качестве начальной точки и что-то вроде a сказать только <a> теги, которые являются прямыми потомками узла контекста.

Другое (главное) это то, что вы строите вывод, используя операторы echo. Это может работать, но также подвержено опечаткам, неверной структуре и т. Д. Этот код использует вызовы API DOM для создания документа.

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