编辑器编辑完成之后的html源码如下
由于项目要求,我们考虑在php端解决这个问题,采用dom的方式,也考虑过正则匹配,但是考虑的意外情况太多,代码可读性也不高
下面是解决的一个demo源码
1 <?php
2 /**
3 * 处理返回界面中多个span不合并的问题
4 *
5 * @param $html
6 *
7 * @return string
8 * 1.查找全部的span 节点
9 * 2.找出节点中需要处理的span节点(只有为span标签的父亲,无兄无弟无子)
10 * 3.遍历节点并处理
11 */
12 function handleHtmlManySpan($html)
13 {
14 $dom=new DOMDocument();
15 $dom->loadHTML($html);
16 $nodes = $dom->getElementsByTagName('span');
17 $waitingNodes = [];
18 foreach ($nodes as $node) {
19 if (isMinimalSpanNode($node)) {
20 $waitingNodes[] = $node;
21 }
22 }
23 foreach ($waitingNodes as $node) {
24 handleMinimalSpanNode($node);
25 }
26 $html = $dom->saveHTML();
27 preg_match('/<body>(.*?)<\/body>/', $html, $matches);
28 return isset($matches[1])?$matches[1]:'';
29 }
30
31 /**
32 * 判断html的dom节点是否是只有span的父亲,无兄无弟无子
33 * @param $node
34 *
35 * @return bool
36 */
37 function isMinimalSpanNode($node)
38 {
39 return $node->parentNode->nodeName=='span' && $node->nextSibling===null&&$node->previousSibling===null && $node->hasChildNodes() && count($node->childNodes)==1 && $node->childNodes[0]->nodeType==XML_TEXT_NODE;
40 }
41
42 /**
43 * 将符合条件的span节点删除,并将样式及内容交还给父亲,并且递归调用
44 * @param $node
45 */
46 function handleMinimalSpanNode($node)
47 {
48 $nodeStyle = $node->getAttribute('style');
49 $nodeValue = $node->nodeValue;
50 $parentNode = $node->parentNode;
51 $parentNode->setAttribute('style', $parentNode->getAttribute('style').$nodeStyle);
52 $parentNode->removeChild($node);
53 $parentNode->nodeValue = $nodeValue;
54 if (isMinimalSpanNode($parentNode)) {
55 handleMinimalSpanNode($parentNode);
56 }
57 }
58
59 $str = '<p><span style="color:red;"><span></span><strong><span style="font-weight:bold;"><span style="font-style: italic;"><span style="font-size:12px;">ceshi</span></span></span></strong></span></p><p><span style="color:red;"><span></span><strong><span style="font-weight:bold;"><span style="font-style: italic;"><span style="font-size:12px;">ceshi</span></span></span></strong></span></p>';
60 echo handleHtmlManySpan($str);
正则替换的方式解决的不够彻底,下面是代码,也可能是我的正则技术不够优秀,欢迎留言
/**
* 解决返回到主页的html显示有多个span的问题
* 将返回的html中的多个span改为1个,将多个span的样式集中为一个
*/
function replaceSpanReg($htmlText)
{
$pattern = "/<span style=\"(.*?)\">/";
$pregNum = preg_match_all($pattern,$htmlText,$matches);
if($pregNum>1){
$style = implode("",$matches[1]);
$strLeftBefore = implode("",$matches[0]);
$strRightBefore = '';
for($i=1;$i<=$pregNum;$i++){
$strRightBefore .= '</span>';
}
$strLeftNow = '<span style="'.$style.'">';
$htmlText = str_replace('\r\n','',$htmlText);
$htmlText = str_replace($strLeftBefore,$strLeftNow,$htmlText);
$htmlText = str_replace($strRightBefore,'</span>',$htmlText);
}
return $htmlText;
}
最上面的代码只能解决最内层的span标签的逐渐删除,下面代码是优化版本,个人感觉更佳
/**
* 处理返回界面中多个span不合并的问题
*
* @param $html
*
* @return string
* 1.查找全部的span 节点
* 2.找出节点中需要处理的span节点(只有为span标签的父亲,无兄无弟无子)
* 3.遍历节点并处理
*/
function handleHtmlManySpan($html)
{
$dom=new DOMDocument();
$dom->loadHTML($html);
$nodes = $dom->getElementsByTagName('span');
$waitingNodes = [];
foreach ($nodes as $node) {
if (isWaitingHandleSpanNode($node)) {
$waitingNodes[] = $node;
}
}
foreach ($waitingNodes as $node) {
handleSpanNode($node);
}
$html = $dom->saveHTML();
preg_match('/<body>(.*?)<\/body>/', $html, $matches);
return isset($matches[1])?$matches[1]:'';
}
/**
* 判断当前的span标签是否需要处理
* 1.如果父标签是span而且没有兄弟标签即处理 ,并且只有一个子元素的时候不是span,也可以有多个子元素
* @param $node
*
* @return bool
*/
function isWaitingHandleSpanNode($node)
{
$isWaiting = false;
//父标签为span且无兄无弟
if($node->parentNode->nodeName=='span' && $node->nextSibling===null&&$node->previousSibling===null)
{
if(count($node->childNodes)!=1){
$isWaiting = true;
}else if(count($node->childNodes)==1 && $node->childNodes[0]->nodeName!='span'){
$isWaiting = true;
}
}
return $isWaiting;
//return $node->parentNode->nodeName=='span' && $node->nextSibling===null&&$node->previousSibling===null;
}
/**
* 将符合条件的span节点删除,并将样式及内容交还给父亲,并且递归调用
* @param $node
*/
function handleSpanNode($node)
{
$nodeStyle = $node->getAttribute('style');
$parentNode = $node->parentNode;
$parentNode->setAttribute('style', $parentNode->getAttribute('style').';'.$nodeStyle);
if(count($node->childNodes)>0){
foreach($node->childNodes as $child)
{
$parentNode->appendChild($child);
}
}
$parentNode->removeChild($node);
if (isWaitingHandleSpanNode($parentNode)) {
handleSpanNode($parentNode);
}
}
$str = '<p><span style="color:red"><span style="font-size:12px"><strong><span style="backgrount:red"><span>ces</span></span></strong></span></span></p>';
echo handleHtmlManySpan($str);