Php 根据标题标记自动生成嵌套目录

Php 根据标题标记自动生成嵌套目录,php,dynamically-generated,Php,Dynamically Generated,你们哪位狡猾的程序员可以向我展示一个优雅的php编码解决方案,用于根据页面上的标题标记自动生成嵌套的目录 因此,我有一个html文档: <h1> Animals </h1> Some content goes here. Some content goes here. <h2> Mammals </h2> Some content goes here. Some content goes here. <h3> Terrestri

你们哪位狡猾的程序员可以向我展示一个优雅的php编码解决方案,用于根据页面上的标题标记自动生成嵌套的目录

因此,我有一个html文档:

<h1> Animals </h1>

Some content goes here.
Some content goes here.

<h2> Mammals </h2>

Some content goes here.
Some content goes here.

<h3> Terrestrial Mammals </h3>
Some content goes here.
Some content goes here.

<h3> Marine Mammals </h3>
Some content goes here.
Some content goes here.

<h4> Whales </h4>
Some content goes here.
Some content goes here.
动物
这里有一些内容。
这里有一些内容。
哺乳动物
这里有一些内容。
这里有一些内容。
陆生哺乳动物
这里有一些内容。
这里有一些内容。
海洋哺乳动物
这里有一些内容。
这里有一些内容。
鲸鱼
这里有一些内容。
这里有一些内容。
更具体地说,我想要一个链接目录,其形式为指向同一页面标题的嵌套链接列表:

目录(由PHP代码自动生成)

  • 动物
  • 哺乳动物
  • 陆生哺乳动物
  • 海洋哺乳动物
  • 鲸鱼

  • 我觉得它并不优雅,但可能有助于了解如何创建一个;)

    它用于查找和操作原始html中的元素

    $htmlcode = <<< EOHTML
    <h1> Animals </h1>
    Some content goes here.
    Some content goes here.
    <h2> Mammals </h2>
    Some content goes here.
    Some content goes here.
    <h3> Terrestrial Mammals </h3>
    Some content goes here.
    Some content goes here.
    <h3> Marine Mammals </h3>
    Some content goes here.
    Some content goes here.
    <h4> Whales </h4>
    Some content goes here.
    Some content goes here.
    EOHTML;
    // simpehtmldom or other dom manipulating library
    require_once 'simple_html_dom.php';
    
    $html = str_get_html($htmlcode);
    
    $toc = '';
    $last_level = 0;
    
    foreach($html->find('h1,h2,h3,h4,h5,h6') as $h){
        $innerTEXT = trim($h->innertext);
        $id =  str_replace(' ','_',$innerTEXT);
        $h->id= $id; // add id attribute so we can jump to this element
        $level = intval($h->tag[1]);
    
        if($level > $last_level)
            $toc .= "<ol>";
        else{
            $toc .= str_repeat('</li></ol>', $last_level - $level);
            $toc .= '</li>';
        }
    
        $toc .= "<li><a href='#{$id}'>{$innerTEXT}</a>";
    
        $last_level = $level;
    }
    
    $toc .= str_repeat('</li></ol>', $last_level);
    $html_with_toc = $toc . "<hr>" . $html->save();
    
    $htmlcode=innertext);
    $id=str_replace(“”,“”,$innerTEXT);
    $h->id=$id;//添加id属性,以便我们可以跳转到此元素
    $level=intval($h->tag[1]);
    如果($level>$last_level)
    $toc=”;
    否则{
    $toc.=str_repeat(“”,$last_level-$level);
    $toc.='';
    }
    $toc.=“
  • ”; $last_level=$level; } $toc.=str_repeat(“
  • ”,$last_level); $html_,其中_toc=$toc。“
    ”$html->save();
    下面是一个使用以下内容的示例:

    $doc=newDOMDocument();
    $doc->loadHTML($code);
    //创建文档片段
    $frag=$doc->createDocumentFragment();
    //创建初始列表
    $frag->appendChild($doc->createElement('ol'));
    $head=&$frag->firstChild;
    $xpath=新的DOMXPath($doc);
    $last=1;
    //获取所有H1、H2、…、H6元素
    foreach($xpath->query('/*[self::h1或self::h2或self::h3或self::h4或self::h5或self::h6]')作为$headline){
    //获取当前标题的级别
    sscanf($headline->tagName,$h%u',$curr);
    //如有必要,移动头部参考
    如果($curr<$last){
    //上移
    对于($i=$curr;$iparentNode->parentNode;
    }
    }如果($curr>$last&&$head->lastChild),则为else{
    //向下移动并创建新列表
    对于($i=$last;$ilastChild->appendChild($doc->createElement('ol'));
    $head=&$head->lastChild->lastChild;
    }
    }
    $last=$curr;
    //添加列表项
    $li=$doc->createElement('li');
    $head->child($li);
    $a=$doc->createElement('a',$headline->textContent);
    $head->lastChild->appendChild($a);
    //构建ID
    $levels=array();
    $tmp=&$head;
    //遍历子树到该子树的片段根节点
    而(!is_null($tmp)&&$tmp!=$frag){
    $levels[]=$tmp->childNodes->length;
    $tmp=&$tmp->parentNode->parentNode;
    }
    $id='sect'。内爆('.',数组_反向($levels));
    //设定目的地
    $a->setAttribute('href','#'。$id);
    //添加锚到标题
    $a=$doc->createElement('a');
    $a->setAttribute('name',$id);
    $a->setAttribute('id',$id);
    $headline->insertBefore($a,$headline->firstChild);
    }
    //将片段附加到文档
    $doc->getElementsByTagName('body')->item(0)->appendChild($frag);
    //回显标记
    echo$doc->saveHTML();
    
    我找到了这个方法,作者是Alex Freeman():

    preg#u match_all('#]*>.*?#',$html#u string,$resultats);
    //重新格式化结果以使其更可用
    $toc=内爆(“\n”,$resultats[0]);
    $toc=str_replace(“”,$toc);
    //将结果插入适当的HTML标记中
    $toc=
    

    材料表


      “.$toc”


    ; 返回$toc;
    在HTML中,标题必须写成:

    <h2><a name="target"></a>Text</h2>
    
    文本
    
    看一下。它允许从嵌套标题生成目录。h1标记后面可以跟任何较低级别的h标记。该类使用递归从文章文本中提取标题

    不应该缩进并以
    1
    开头?哦,我的错!我将编辑我的问题HTML内容是如何生成的?不是吗hat静态用户输入?如果是数据(数据库、阵列)将标题放在
    h
    -标记中,如果您只有一个包含所有内容的字符串,那么会容易得多;然后您必须首先分析
    h
    -标记的字符串。HTML位于数据库中,它包含一个字符串变量。我尝试了这一点。目前,它在$frag->appendChild上抛出一个致命错误。此代码有效只有当你的层次结构中没有像一个
    h1
    后面跟着一个
    h3
    这样的缺口时,这篇文章才是古老的,…但很有用!当我使用这个脚本时,我注意到OL和LI标记在结尾没有闭合。我需要在结尾处添加“$toc.=stru repeat(',$level);`在循环之外。
        preg_match_all('#<h[4-6]*[^>]*>.*?<\/h[4-6]>#',$html_string,$resultats);
    
        //reformat the results to be more usable
        $toc = implode("\n",$resultats[0]);
        $toc = str_replace('<a name="','<a href="#',$toc);
        $toc = str_replace('</a>','',$toc);
        $toc = preg_replace('#<h([4-6])>#','<li class="toc$1">',$toc);
        $toc = preg_replace('#<\/h[4-6]>#','</a></li>',$toc);
    
        //plug the results into appropriate HTML tags
        $toc = '<div id="toc"> 
        <p id="toc-header">Table des matières</p>
        <hr />
        <ul>
        '.$toc.'
        </ul>
        </div><br /><br />';
    
        return $toc;
    
    <h2><a name="target"></a>Text</h2>