zoukankan      html  css  js  c++  java
  • php版getElementsByTagName , php版根据标签名获取 标签节点列表.模拟javascript的getElementsByTagName函数

    新鲜出炉,昨天周末写的 php版getElementsByTagName模拟javascript的getElementsByTagName , 根据标签名获取 标签列表.(多层嵌套也正常匹配)

       以下凑足200字....

         /*
        * 功能: php版getElementsByTag , 根据标签名获取 标签列表.(多层嵌套也正常匹配)
        * 参数:
                $str 被查找的字符串;
                $start_tag 开始标记;
                $close_tag 关闭标记;

                [可选] $tag_slashe 加在 标记 之前, 用于转义的字符(目的是防止混淆正常字符和标记), 默认false;
                [可选] $begin_pos , 用于指定开始查找的位置, 默认0 . 该参数在模仿类似js的语法: obj.getElementsByTagName() , 查找指定对象之下的标签列表时非常有用处;
                [可选] $end_pos , 用于指定结束位置, 默认0 .

        * 返回: 查找成功返回数组列表, 查找没有结果则返回false.
        * 作者: 王奇疏
        */  

      1 <?php
      2     echo '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
      3 
      4     /*
      5     * 功能: php版getElementsByTag , 根据标签名获取 标签列表.(多层嵌套也正常匹配)
      6     * 参数: 
      7             $str 被查找的字符串; 
      8             $start_tag 开始标记; 
      9             $close_tag 关闭标记; 
     10 
     11             [可选] $tag_slashe 加在 标记 之前, 用于转义的字符(目的是防止混淆正常字符和标记), 默认false; 
     12             [可选] $begin_pos , 用于指定开始查找的位置, 默认0 . 该参数在模仿类似js的语法: obj.getElementsByTagName() , 查找指定对象之下的标签列表时非常有用处;
     13             [可选] $end_pos , 用于指定结束位置, 默认0 . 
     14 
     15     * 返回: 查找成功返回数组列表, 查找没有结果则返回false.
     16     * 作者: 王奇疏
     17     */
     18     function getElementsByTag( $str , $start_tag , $close_tag , $tag_slashe=false , $begin_pos=0 , $end_pos=0 ) {
     19             $list = array(  );
     20             
     21             $start = $begin_pos;// 临时存储字符位置
     22             $end = $end_pos;
     23             $start_pos = $close_pos = 0; // 每一对标记的起止位置
     24             
     25             $stack = array(); // 一个数组, 用来借助栈的作用保存上一次循环的数据.    
     26             
     27             $s_len = strlen( $start_tag ); // 标记本身的长度
     28             $c_len = strlen( $close_tag );
     29             
     30             $slashe_ord = ord( $tag_slashe ); // 转义符
     31     
     32             while( false !== ( $start = stripos( $str , $start_tag , $start ) ) ) {
     33 
     34                 $i = 0; // 标记 计数器 
     35                 $j = 1024; // 最大循环计数器 , 防死循环
     36 
     37                 $start_pos = $start; // 初始化每对标记的起止位置
     38                 $close_pos = $start_pos + $s_len; // (close_tag的开始位置应在start_tag之后)
     39                 $stack = array();        
     40                 
     41                 while ( $j > 0 ){
     42                     // 一次搜索两种标记: $start_tag , $close_tag
     43                     if ( $start_pos > $start ) {
     44                         $start_pos = stripos( $str , $start_tag , $start_pos );
     45                     }
     46                     $close_pos = stripos( $str , $close_tag , $close_pos );
     47                     
     48                     // 如果 找到的标记 的前面一个字符是转义符 , 则再重新搜索一次.
     49                     if ( false !== $start_pos && $slashe_ord === ord( $str[ $start_pos - 1 ] ) ) {
     50                         $start_pos = stripos( $str , $start_tag , $start_pos + $s_len );
     51                     }
     52                     
     53                     if ( false !== $close_pos && $slashe_ord === ord( $str[ $close_pos - 1 ] ) ) {
     54                         $close_pos = stripos( $str , $close_tag , $close_pos + $c_len );
     55                     }
     56                     
     57                     // 把 关闭标记的位置 存进栈内, 保持只存2条.
     58                     if ( $j === 1024 ) { 
     59                         $stack[] = $close_pos; // (第1次多存1条) 
     60                     }
     61                     $stack[] = $close_pos;
     62 
     63                     // 开始标记 大于 上一个关闭标记,  
     64                     if ( $start_pos > ( $prev = array_shift( $stack ) ) ) {
     65                         $prev += $c_len;
     66                         break;
     67                     }
     68                     // 找不到开始标签时, 从哪开头?
     69                     elseif ( false === $start_pos ) {
     70                         $prev += $c_len;
     71                         break;
     72                     }
     73                     // 找不到闭合的标签时, 从哪开头?怎么处理?
     74                     elseif ( false === $close_pos ) {
     75                         show_match_error( $str , $start , $start_tag , $close_tag  );
     76                         return false;
     77                     }
     78                     else {
     79                         $start_pos += $s_len;
     80                         $close_pos += $c_len;
     81                     }
     82                     
     83                     --$j;
     84                 }
     85 
     86                 if ( $j == 0 ) {
     87                     show_match_error( $str , $start , $start_tag , $close_tag  );
     88                     return false;
     89                 }
     90                 
     91                 $list[] = substr( $str , $start , $prev - $start );
     92                 $start = $prev;
     93 
     94             }
     95             return $list;
     96     }
     97     
     98     // 仅仅用于显示匹配错误信息的函数
     99     function show_match_error( $str , $sub_start , $start_tag , $close_tag ) {
    100         $count_line = substr( $str , 0 , $sub_start );
    101         $count_line = substr_count( $count_line , PHP_EOL ) + 1;
    102 
    103         trigger_error( '<div style="padding: 10px;font-family:tahoma;font-size:12px; border:1px solid #c1c1c1; "><strong>出现标签未闭合的错误:</strong><br /><br />程序设定的<br />开始标记是: <font color="red">'.htmlspecialchars( "{$start_tag} " ).'</font> <br />闭合标记是: <font color="red">'.htmlspecialchars( "{$close_tag} " ).'</font> <br /><font color="red"><br />现检查到有一个标记没有闭合,不符合xhtml规范,已经停止匹配.</font><br /><br />未闭合标记的位置在原文中从<font color="red">第'.$count_line.'行</font>开始 , 在周围缺少闭合标签. <br />(<font color="red">第'.$count_line.'行</font>)大约是从以下字符开始, 请查看您原来的数据,检查标记是否闭合完整: <br />"<pre>'.htmlspecialchars( substr( $str , $sub_start , 80 ) ).'</pre> "</div>' ); 
    104     }
    105     



    测试数据
    <?php
    
        // 测试数据:-----------
        $str = <<<EOF
            <html>
            <head>
                <title> 测试模板文件 </title>
                <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
            </head>
    
            <body>
                <br />
                1.变量:<br />
                $title.<br />
                \$title2这里的变量对$标记使用了转义符号\$,所以不会被当成php变量\$title2来解释<br /><br />
    
                1.2<br />
                链式变量:$shop->getobj()->show(2)<br /><br />
    
                2.分支语句<br />
                欢迎~if( $user == 'admin' ){  管理\~\}员hhhhhhhhhhhhh}else{  : echo $user; }~登陆<br /><br /><br />
                ~if( $user == 'admin' ){ 
                    : 
                    echo 'set first char to :   ,  then you can  write php syntax here.';
                    var_dump( 'hello php syntax.' );
    
                    if( $ty ){
                        echo 'good.........';
                    }
                    else{
                        echo 'bad..........';
                    }
    
                    if( $ty ){
                        echo 'good.........';
                    }
                    else{
                        echo 'bad..........';
                    }
    
    
                    if( $ty ){
                        echo 'good.........';
    
    
                    if( $ty ){
                        echo 'good.........';
                    }
                    else{
                        echo 'bad..........';
                    }
    
    
    
                    }
                    else{
                        echo 'bad..........';
                    }
    
    
                }
                else(){
                    no : ,  you can  write  html here .
                    \}
                }
                ~<br /><br /><br />
                
                3.函数标签<br />
                直接调用函数标签,作用是输出函数:<var_dump( 'abc' )><br /><br />
                
                4.循环标签.<br />
                <loop $array $i=0><br />
                    ·[<a href="#">$sort</a>] <a href="#author">$user </a> : $title. <img src="./yes.jpg" alt="图文提示" /> - $time<br />
                </loop><br /><br />
            <li>
                <li>
                    <li>
                    </li>
                </li>
            </li>
            <li>
                <li>
                </li>
            </li>
    
    
            <div id="test">
                <div>
    
                    <div>
                        aaaaa
                    </div>
    
                    <div>
                        <div>
                            <div>
                                <div>
                                    bbb    <div>
                                    .ccc.
                                            </div>
                                </div>
                            </div>
                        </div>
                    </div>
    
                    <div>
                        dddddd
                    </div>
    
                    <div>
                        eeeeeeeeee
                    </div>
                </div>
    
                <div>
                    ffff
                </div>
                ggggggggggggg
            </div>
    
            <div>h</div>
            <div>i</div>
    
            <div></div>
            <div>
            </div>
    
    
            <div>1</div>
            <div>2</div>
    
            <div>
            </div>
    
    
    EOF;
        
        $test = getElementsByTag( $str , '<div' , '</div>' , '\\' );
        // $test = getElementsByTag( $str , '{' , '}' , '\\' );
        // $test = getElementsByTag( $str , '~if' , '~' , '\\' );
        // $test = getElementsByTag( $str , '<li' , '</li>' , '\\' );
        echo '<pre>';print_r( $test );echo '</pre>';exit;


     如果标签正常闭合,就能正常正确地匹配节点,测试结果如下图:
    --------------

     
    2.如果标签没有闭合,提示错误
    --------------

  • 相关阅读:
    Could not obtain transaction-synchronized Session for current thread
    Spring 具名参数NamedParameterJdbcTemplate
    Could not load driverClass jdbc:mysql://localhost:3306/spring
    Spring 使用AspectJ的三种方式
    Excel 若某列包含某个字符则特定列显示特定字符
    使用Spring的隐式注解和装配以及使用SpringTest框架
    Eclipse Oxygen 解决 自动导包的问题
    C3P0 WARN: Establishing SSL connection without server's identity verification is not recommended
    Eclipse 多行复制并且移动失效
    正则表达式 使用代码
  • 原文地址:https://www.cnblogs.com/wangqishu/p/3063035.html
Copyright © 2011-2022 走看看