Introduction
The best solution have seen so far is using HTML Tidy
http://tidy.sourceforge.net/
Beyond converting the format of a document, Tidy is also able to convert deprecated HTML tags into their cascading style sheet (CSS) counterparts automatically through the use of the clean option. The generated output contains an inline style declaration.
It also ensures that the HTML document is xhtml
compatible
Example
$code ='<p>
<strong>
<span style="font-size: 14px">
<span style="color: #006400">
<span style="font-size: 14px">
<span style="font-size: 16px">
<span style="color: #006400">
<span style="font-size: 14px">
<span style="font-size: 16px">
<span style="color: #006400">This is a </span>
</span>
</span>
</span>
</span>
</span>
</span>
<span style="color: #006400">
<span style="font-size: 16px">
<span style="color: #b22222">Test</span>
</span>
</span>
</span>
</span>
</strong>
</p>';
If you RUN
$clean = cleaning($code);
print($clean['body']);
Output
<p>
<strong>
<span class="c3">
<span class="c1">This is a</span>
<span class="c2">Test</span>
</span>
</strong>
</p>
You can get the CSS
$clean = cleaning($code);
print($clean['style']);
Output
<style type="text/css">
span.c3 {
font-size: 14px
}
span.c2 {
color: #006400;
font-size: 16px
}
span.c1 {
color: #006400;
font-size: 14px
}
</style>
Our the FULL HTML
$clean = cleaning($code);
print($clean['full']);
Output
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<style type="text/css">
/*<![CDATA[*/
span.c3 {font-size: 14px}
span.c2 {color: #006400; font-size: 16px}
span.c1 {color: #006400; font-size: 14px}
/*]]>*/
</style>
</head>
<body>
<p>
<strong><span class="c3"><span class="c1">This is a</span>
<span class="c2">Test</span></span></strong>
</p>
</body>
</html>
Function Used
function cleaning($string, $tidyConfig = null) {
$out = array ();
$config = array (
'indent' => true,
'show-body-only' => false,
'clean' => true,
'output-xhtml' => true,
'preserve-entities' => true
);
if ($tidyConfig == null) {
$tidyConfig = &$config;
}
$tidy = new tidy ();
$out ['full'] = $tidy->repairString ( $string, $tidyConfig, 'UTF8' );
unset ( $tidy );
unset ( $tidyConfig );
$out ['body'] = preg_replace ( "/.*<body[^>]*>|</body>.*/si", "", $out ['full'] );
$out ['style'] = '<style type="text/css">' . preg_replace ( "/.*<style[^>]*>|</style>.*/si", "", $out ['full'] ) . '</style>';
return ($out);
}
================================================
Edit 1 : Dirty Hack (Not Recommended)
================================================
Based on your last comment its like you want to retain the depreciate style .. HTML Tidy
might not allow you to do that since its depreciated
but you can do this
$out = cleaning ( $code );
$getStyle = new css2string ();
$getStyle->parseStr ( $out ['style'] );
$body = $out ['body'];
$search = array ();
$replace = array ();
foreach ( $getStyle->css as $key => $value ) {
list ( $selector, $name ) = explode ( ".", $key );
$search [] = "<$selector class="$name">";
$style = array ();
foreach ( $value as $type => $att ) {
$style [] = "$type:$att";
}
$replace [] = "<$selector style="" . implode ( ";", $style ) . ";">";
}
Output
<p>
<strong>
<span style="font-size:14px;">
<span style="color:#006400;font-size:14px;">This is a</span>
<span style="color:#006400;font-size:16px;">Test</span>
</span>
</strong>
</p>
Class Used
//Credit : http://stackoverflow.com/a/8511837/1226894
class css2string {
var $css;
function parseStr($string) {
preg_match_all ( '/(?ims)([a-z0-9, s.:#_-@]+){([^}]*)}/', $string, $arr );
$this->css = array ();
foreach ( $arr [0] as $i => $x ) {
$selector = trim ( $arr [1] [$i] );
$rules = explode ( ';', trim ( $arr [2] [$i] ) );
$this->css [$selector] = array ();
foreach ( $rules as $strRule ) {
if (! empty ( $strRule )) {
$rule = explode ( ":", $strRule );
$this->css [$selector] [trim ( $rule [0] )] = trim ( $rule [1] );
}
}
}
}
function arrayImplode($glue, $separator, $array) {
if (! is_array ( $array ))
return $array;
$styleString = array ();
foreach ( $array as $key => $val ) {
if (is_array ( $val ))
$val = implode ( ',', $val );
$styleString [] = "{$key}{$glue}{$val}";
}
return implode ( $separator, $styleString );
}
function getSelector($selectorName) {
return $this->arrayImplode ( ":", ";", $this->css [$selectorName] );
}
}