开发者

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:

  1. 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 that XML.normalize() just discards spaces, regardless of ignoreWhitespace=false.
  2. 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.
  3. Replace all <style> nodes with <span style="...">, containing the combined style attributes. Your example had <font> tags, but those are not supported in HTML5.
  4. 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]]><" );
        }
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜