AS3 HTML to CSS3 and back
using php, how would you convert...
<P ALIGN="LEFT">
<FONT FACE="Helvetica" SIZE="25" COLOR="#000000" LETTERSPACING="0" KERNING="0">
<B>
<I>Cras id sapien odio. Vestibulum </I>
</B>
<FONT COLOR="#006633">
开发者_运维技巧 <B>
<I>ante</I>
</B>
<FONT SIZE="19">
ipsum primis in faucibus orci luctus et <I>ante ultrices</I> posuere cubilia Curae;
<FONT COLOR="#000000"></FONT>
</FONT>
</FONT>
</FONT>
</P>
to something like
<p><font style="etc">Cras id sapien odio. Vestibulum</font><font style="etc">ante</font><font style="etc">ipsum primis in faucibus orci luctus et ante ultrices posuere cubilia Curae</font></p>
I am trying to flatten out and reduce recursion in the DOM, and then I have to switch to back to html 1.0. This code I am writing is moving HTML between flash and css3 so ios users can view the html animation, and everyone else is viewing flash. Unfortuantely the first html is what flash outputs. I am messing around with DOMDocument, any ideas?
Alright, I think I have it now. It took a bit longer, and it looks a little less tidy than I hoped it would, but I wrote a static utility class to take care of the "translation" from Flash fonts to HTML. It works like this:
- Wrap all text into
<![CDATA[]]>
tags. This is the only way to safely preserve whitespace when using XML transformation, as it turns out - it took me almost three hours to figure out thatXML.normalize()
just discards spaces, regardless ofignoreWhitespace=false
. - Normalize all font information into
<style>
nodes. This replaces all<b>
,<u>
, etc. tags, but keeps the DOM hierarchy. All style information is transformed into attributes with the same names Flash uses for CSS parsing internally. - Replace all
<style>
nodes with<span style="...">
, containing the combined style attributes. Your example had<font>
tags, but those are not supported in HTML5. - Unwrap the
<![CDATA[]]>
elements.
The result is still not flattened, but nested <span>
elements are allowed, and it does the job: I pasted the output into a simple html page and it looks pretty much the same as it does in Flash.
Note: I haven't tested all of the allowed HTML elements in Flash (<img>
, etc.), so I can't guarantee it will work for everything - but it should do fine on all the elements in your example.
Here's my class, looking forward to your comments and criticism:
Usage: var html:String = XMLTextUtil.flashTextToHtml (textField.htmlText);
package
{
public class XMLTextUtil
{
private static var mapping : Array = [ {html:"align", xml:"stageAlign"},
{html:"face", xml:"fontFamily"},
{html:"size", xml:"fontSize"},
{html:"blockindent", xml:"marginLeft"},
{html:"indent", xml:"textIndent"},
{html:"leftmargin", xml:"marginLeft"},
{html:"rightmargin", xml:"marginRight"},
{html:"letterspacing", xml:"letterSpacing"} ];
private static var typeMapping : Array = [ {attribute:"letterSpacing", type:"px"},
{attribute:"fontFamily", type:""},
{attribute:"fontSize", type:"px"},
{attribute:"fontStyle", type:""},
{attribute:"fontWeight", type:""},
{attribute:"textAlign", type:""},
{attribute:"textIndent", type:"px"},
{attribute:"textDecoration", type:""},
{attribute:"marginLeft", type:"px"},
{attribute:"marginRight", type:"px"} ];
private static function applyStyles ( html : XML ) : XML
{
var root : XML = applyTag( html );
for each ( var child:XML in html.children( ))
{
var kind : String = child.nodeKind( );
if ( kind == "element")
{
var next : XML = applyStyles( child );
if (next.name( ) != "span" || next.children( ).length( ) > 0)
{
root.appendChild( next );
}
}
else if (kind == "text") root.appendChild( child.copy( ) );
}
return root;
}
private static function applyTag ( html : XML ) : XML
{
var root : XML;
switch ( html.name( ).toString( ) )
{
case "style":
root = createElement( "span" );
root.@style = styleElementToString( html );
break;
case "p":
root = createElement( "p" );
break;
default:
root = cloneElement( html );
break;
}
return root;
}
private static function cloneElement ( html : XML ) : XML
{
var node : XML = createElement( html.name( ) );
for each (var attr:XML in html.attributes( ))
{
node["@" + attr.name( )] = html["@" + attr.name( )];
}
return node;
}
private static function createElement ( str : String) : XML
{
return new XML( "<" + str + " />" );
}
public static function flashTextToHtml ( str : String ) : String
{
XML.prettyPrinting = false;
XML.ignoreWhitespace = true;
var wrap : String = wrapTextInCdata( "<text>" + str + "</text>" );
var html : XML = new XML( wrap );
html = normalizeStyleTags( html );
var newHtml : XML = transformToHtml5( html );
return unwrapTextFromCdata( newHtml );
}
private static function getCssName (str : String ) : String
{
return str.replace( /[A-Z]/g, "-$&").toLowerCase( );
}
private static function getStyleName ( str : String ) : String
{
for each ( var map:Object in mapping)
{
if (str == map.html ) return map.xml;
}
return str;
}
private static function getCssType (str : String) : String
{
for each (var map:Object in typeMapping)
{
if (str == map.attribute) return map.type;
}
return "";
}
private static function normalizeStyleTags ( xmlElement : XML ) : XML
{
var xml : XML;
var child : XML;
var style : XML = new XML( "<style />" );
var name:String = xmlElement.name( ).toString( ).toLowerCase( );
switch ( name )
{
case "font":
case "textformat":
xml = style;
break;
case "b":
xml = style;
xml.@fontWeight = "bold";
break;
case "i":
xml = style;
xml.@fontStyle = "italic";
break;
case "u":
xml = style;
xml.@textDecoration = "underline";
break;
case "p":
xml = new XML( "<p />" );
xml.appendChild( style );
xml = style;
default:
xml = new XML( "<" + name + " />" );
break;
}
for each ( child in xmlElement.attributes( ))
{
var attname : String = getStyleName( child.name( ).toString( ).toLowerCase( ) );
xml["@" + attname] = xmlElement["@" + child.name( )];
switch (xml["@" + attname].toString( ))
{
case "LEFT":
case "RIGHT":
case "CENTER":
xml["@" + attname] = xml["@" + attname].toLowerCase( );
}
}
for each ( child in xmlElement.children( ))
{
var kind : String = child.nodeKind( );
if ( kind == "element") xml.appendChild( normalizeStyleTags( child ) );
else if (kind == "text")
xml.appendChild( new XML( "<![CDATA[" + child.valueOf( ) + "]]>" ) );
}
return xml;
}
private static function styleElementToString ( styleElement : XML ) : String
{
var style : Object = {};
var name : String = "";
var string : String = "";
for each ( var attribute:XML in styleElement.attributes( ))
{
name = attribute.name( ).toString( );
style[name] = styleElement.attribute( name ).valueOf( );
}
for ( name in style)
{
if ( style[name] != null)
string += getCssName( name ) + ":" + style[name] + getCssType( name ) + ";";
}
return string;
}
private static function transformToHtml5 ( xmlText : XML ) : XML
{
var root : XML = new XML( "<text />" );
for each ( var p:XML in xmlText.p)
{
root.appendChild( applyStyles( p ) );
}
return root;
}
public static function unwrapTextFromCdata (xmlText : XML) : String
{
return xmlText.toXMLString( ).replace( /(\<\!\[CDATA\[)|(\]\]\>)/g, "" );
}
public static function wrapTextInCdata (htmlText : String) : String
{
return htmlText.replace( /(?:\>)([\s|\w]+)(?:\<)/g, "><![CDATA[$1]]><" );
}
}
}
精彩评论