PHP создает рекурсивный список тегов заголовков из DOM - PullRequest
0 голосов
/ 02 июня 2018

Я хочу проанализировать HTML-код для создания вложенной навигации на основе заголовков в этом документе.

Массив, подобный этому, - это то, что я пытаюсь создать:

[
  'name' => 'section 1',
  'number' => '1',
  'level' => 1,
  'children' => [
    [
      'name' => 'sub section 1',
      'number' => '1.1',
      'level' => 2,
      'children' => []
    ],
    [
      'name' => 'sub section 2',
      'number' => '1.2',
      'level' => 2,
      'children' => []
    ]
  ],
]

Таким образом, если документ имеет H3 после H2, код может затем проанализировать его и создать вложенный массив с дочерними элементами для каждого последующего уровня заголовков H

Я полагаю, что для этого нужно сделать несколько основных вещей:

  • Получить все заголовки
  • Рекурсивный цикл (H3 после H2 должен быть дочерним в массиве)
  • Создать номер раздела 1.1.1 или 1.1.2например

Это мой код для извлечения заголовков:

$dom = new \DomDocument();
$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

// Extract the heading structure
$xpath = new \DomXPath($dom);
$headings = $xpath->query('//h1|//h2|//h3|//h4|//h5|//h6');

Я пытался создать рекурсивную функцию, но я не уверен, что лучший способ получитьэто работает

1 Ответ

0 голосов
/ 02 июня 2018

Это очень сложно проверить, так как это будет зависеть от того, насколько сложен HTML и какие страницы вы используете.Кроме того, так как код делает многое, я оставлю вам решать, что он делает, поскольку объяснение будет продолжаться какое-то время.XPath был создан с использованием XPath, чтобы выбрать все элементы между двумя конкретными элементами в качестве ссылки для выбора данных между двумя тегами.Источником теста (test.html) является просто ....

<html>
<head>
</head>
<body>
    <h2>Header 1</h2>
    <h2>Header 2</h2>
    <h3>Header 2.1</h3>
    <h4>Header 2.1.1</h4>
    <h2>Header 3</h2>
    <h3>Header 3.1</h3>
</body>
</html>

Фактический код: ...

function extractH ( $level, $xpath, $dom, $position = 0, $number = ''  )  {
    $output = [];
    $prevLevel = $level-1;
    $headings = $xpath->query("//*/h{$level}[count(preceding-sibling::h{$prevLevel})={$position}]");
    foreach ( $headings as $key => $heading )   {
        $sectionNumber = ltrim($number.".".($key+1), ".");
        $newOutput = ["name" => $heading->nodeValue,
            "number" => $sectionNumber,
            "level" => $level
            ];
        $children = extractH($level+1, $xpath, $dom, $key+1, $sectionNumber);
        if ( !empty($children) )    {
            $newOutput["children"] = $children;
        }
        $output[] =$newOutput;
    }

    return $output;
}

$html = file_get_contents("test.html");
$dom = new \DomDocument();
$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$xpath = new \DomXPath($dom);
$output = extractH(2, $xpath, $dom);
print_r($output);

У вызова extractH() мало параметров.Поскольку образец HTML начинается только с тегов h2 (без h1), тогда первый параметр равен 2. Затем объекты XPath и DomDocument для работы.

...