您的位置:首页 > Web前端 > JavaScript

php版getElementsByTagName , php版根据标签名获取 标签节点列表.模拟javascript的getElementsByTagName函数

2013-05-06 16:25 555 查看
新鲜出炉,昨天周末写的 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.
* 作者: 王奇疏
*/  

<?php
echo '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';

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

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

* 返回: 查找成功返回数组列表, 查找没有结果则返回false.
* 作者: 王奇疏
*/
function getElementsByTag( $str , $start_tag , $close_tag , $tag_slashe=false , $begin_pos=0 , $end_pos=0 ) {
$list = array(  );

$start = $begin_pos;// 临时存储字符位置
$end = $end_pos;
$start_pos = $close_pos = 0; // 每一对标记的起止位置

$stack = array(); // 一个数组, 用来借助栈的作用保存上一次循环的数据.

$s_len = strlen( $start_tag ); // 标记本身的长度
$c_len = strlen( $close_tag );

$slashe_ord = ord( $tag_slashe ); // 转义符

while( false !== ( $start = stripos( $str , $start_tag , $start ) ) ) {

$i = 0; // 标记 计数器
$j = 1024; // 最大循环计数器 , 防死循环

$start_pos = $start; // 初始化每对标记的起止位置
$close_pos = $start_pos + $s_len; // (close_tag的开始位置应在start_tag之后)
$stack = array();

while ( $j > 0 ){
// 一次搜索两种标记: $start_tag , $close_tag
if ( $start_pos > $start ) {
$start_pos = stripos( $str , $start_tag , $start_pos );
}
$close_pos = stripos( $str , $close_tag , $close_pos );

// 如果 找到的标记 的前面一个字符是转义符 , 则再重新搜索一次.
if ( false !== $start_pos && $slashe_ord === ord( $str[ $start_pos - 1 ] ) ) {
$start_pos = stripos( $str , $start_tag , $start_pos + $s_len );
}

if ( false !== $close_pos && $slashe_ord === ord( $str[ $close_pos - 1 ] ) ) {
$close_pos = stripos( $str , $close_tag , $close_pos + $c_len );
}

// 把 关闭标记的位置 存进栈内, 保持只存2条.
if ( $j === 1024 ) {
$stack[] = $close_pos; // (第1次多存1条)
}
$stack[] = $close_pos;

// 开始标记 大于 上一个关闭标记,
if ( $start_pos > ( $prev = array_shift( $stack ) ) ) {
$prev += $c_len;
break;
}
// 找不到开始标签时, 从哪开头?
elseif ( false === $start_pos ) {
$prev += $c_len;
break;
}
// 找不到闭合的标签时, 从哪开头?怎么处理?
elseif ( false === $close_pos ) {
show_match_error( $str , $start , $start_tag , $close_tag  );
return false;
}
else {
$start_pos += $s_len;
$close_pos += $c_len;
}

--$j;
}

if ( $j == 0 ) {
show_match_error( $str , $start , $start_tag , $close_tag  );
return false;
}

$list[] = substr( $str , $start , $prev - $start );
$start = $prev;

}
return $list;
}

// 仅仅用于显示匹配错误信息的函数
function show_match_error( $str , $sub_start , $start_tag , $close_tag ) {
$count_line = substr( $str , 0 , $sub_start );
$count_line = substr_count( $count_line , PHP_EOL ) + 1;

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>' );
}


测试数据

<?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.如果标签没有闭合,提示错误
--------------

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐