Archive for the ‘ Adobe AIR ’ Category

Static initializers in AS3

Does ActionScript 3 have static initializers like Java?

You bet it does!

First of all, what is a static initializer? Simply put, it’s a block of executable code used to initialise a class. They’re also called “static constructors” in C#.

Here’s a class that detects and stores Flash Player version information:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class FlashPlayerVersion
{
    /* Inicializador de Bloque estático */
    {
        trace("Initialising class FlashPlayerVersion");
        var a:Array = Capabilities.version.split(" ");
        platform = a[0]; // "WIN", "MAC", "UNIX", etc.
        a = a[1].split(",");
        majorVersion = int(a[0]);
        minorVersion = int(a[1]);
        buildNumber = int(a[2]);
        internalBuildNumber = int(a[3]);
    }
    public static var platform:String;
    public static var majorVersion:int;
    public static var minorVersion:int;
    public static var buildNumber:int;
    public static var internalBuildNumber:int;
}

The version information provided by the Capabilities class is in string format, so we need to parse it once. Since the variables holding these values are static, they must be initialised in a static block.

The code in the static block is run when the class is first loaded. You can have multiple static blocks, and they’ll all be executed in the order in which they appear textually within the source.

Here’s a small bit of MXML to test out the FlashPlayerVersion class:

1
2
3
4
5
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
  <mx:Button label="Click Me!"
     click="trace('Build number:', FlashPlayerVersion.buildNumber)" />
</mx:Application>

When you click the button for the first time, the program will trace “Initialising class FlashPlayerVersion” followed by the Flash Player build number. The static initializer is run only once, when the class is first loaded in the virtual machine, which happens when it is first referenced in the application (in our case the click handler).

Original post:manishjethani.com

XSLT en Air

Entrada muy interesante en MadeInFlex.

Copio y pego:

Aunque no salga en la lista de prestaciones, AIR soporta de forma indirecta la transformación de XML’s a través de XSLT’s. El kit de la cuestión recae en el uso del componente HTML o mejor aún de HTMLLoader, teniendo en cuenta que el componente HTML es un wrapper de HTMLLoader en Flex.

El componente HTMLLoader lo que hace es delegar la interpretación y renderizado de código html en WebKit (el core de Safari). Y es este, WebKit, el que por sí mismo soporta XSLT de una forma muy sencilla.

A continuación muestro una pequeña prueba de concepto de cómo poder invocar xslt’s contra xml’s a través de una pequeña clase.

En el navegador, una forma de aplicar xslt a un xml directamente sería hacer lo siguiente:

Creamos el xml que queremos transformar (model.xml)

1
2
3
4
5
6
7
<?xml-stylesheet href="transformacion.xsl" type="text/xsl" ?>
<numbers>
  <number>2</number>
  <number>11</number>
  <number>100</number>
  <number>-5</number>
</numbers>

Creamos la xlst que queremos (transformacion.xsl)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
  <xsl:template match="/"> <!-- Set up web page -->
    <html>
      <head>
        <title>Squares</title>
        <style> <!-- Put a little CSS in -->
           body { font-family: arial,helvetica; }
           h1   { font-size: 14pt }
           p    { font-size: 10pt}
        </style>
      </head>
      <body>
        <h1 id="toc-squares">Squares</h1>
        <xsl:apply-templates/>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="number">
    <xsl:variable name="value" select="."/>
    <p>
      <xsl:text>The square of </xsl:text>
      <xsl:value-of select="$value"/>
      <xsl:text> is </xsl:text>
      <xsl:value-of select="$value * $value"/>.</p>
  </xsl:template>
</xsl:stylesheet>

3. Aplicamos la xlst al xml mediante una processing instruction del estilo

Si cargamos modelo.xml en un navegador, éste parseará el xml y le aplicará la xslt indicada en la processing instruction dando como resultado un html (que es el que visualizaremos en el navegador).

Una de las funcionalidades que no podemos olvidar de HTMLControl es que es operativo aunque no esté incluido en la displayList. Podemos crear una clase que, usando un HTMLLoader pero sin representarlo visualmente, intercepte el XML, le añada la processing instruction y que capture el html resultante.

Este sería el circuito normal. Mediante HTMLLoader.loadString podemos cargar en el componente un xhtml generado al vuelo (el que queramos concatenado con la processing instruction). El problema de esto es que por algún extraño motivo, loadString no carga la xsl de transformación. Pero sí que funciona utilizando html.load (). Para paliar este comportamiento anómalo la siguiente clase lo que hace es crear un fichero temporal (que después se elimina) y que es el que el HTMLLoader cargará.

A continuación se muestra la clase XSLTProcessor.as

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package com.mif.air.xsltProcessor
{
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.filesystem.File;
    import flash.filesystem.FileMode;
    import flash.filesystem.FileStream;
    import flash.html.HTMLLoader;
    import flash.net.URLRequest;

    [Event (name="complete", type="flash.events.Event")]
    public class XSLTProcessor extends EventDispatcher
    {
        private var html:HTMLLoader;
        private var _output:String;

        private var tmpXMLFile:File;
        private var tmpXSLTfile:File;

        public var xmlContent:XML;
        public var xslt:File;

        public function XSLTProcessor()
        {
            html = new HTMLLoader ();
            html.addEventListener (Event.COMPLETE, htmlCompleteHandler);
        }

        public function parse ():void
        {
            if (this.xmlContent && this.xslt)
            {
                tmpXMLFile = File.applicationStorageDirectory.resolvePath ("tmpXML.xml");
                tmpXSLTfile = File.applicationStorageDirectory.resolvePath (xslt.name)
                xslt.copyTo (tmpXSLTfile, true);

                var alteredXML:String = "<?xml-stylesheet href=\"" + tmpXSLTfile.url + "\" type=\"text/xsl\" ?>" + this.xmlContent.toString();

                var fs:FileStream = new FileStream ();
                fs.open(tmpXMLFile,FileMode.WRITE);
                fs.writeUTFBytes (alteredXML);
                fs.close();

                html.load ( new URLRequest (tmpXMLFile.url));
            }
        }

        private function htmlCompleteHandler (event:Event):void
        {
            this._output = html.window.document.documentElement.outerHTML;

            this.dispatchEvent (new Event (Event.COMPLETE));
            tmpXMLFile.deleteFile();
            tmpXMLFile = null;
        }

        [Bindable ("complete")]
        public function get output ():String
        {
            return this._output;
        }
    }
}

Una forma de usarlo sería desde una aplicación AIR basada en Flex:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
    creationComplete="xmlLoader.send()">

    <mx:Script>
        <![CDATA[
            import com.mif.air.xsltProcessor.XSLTProcessor;

            private function resultHandler ():void
            {
                var xsltProcessor:XSLTProcessor = new XSLTProcessor ();
                xsltProcessor.xmlContent = xmlLoader.lastResult as XML;
                xsltProcessor.xslt = File.applicationDirectory.resolvePath ("squareAsHTML.xsl");
                xsltProcessor.addEventListener ("complete", parseComplete);
                xsltProcessor.parse();
            }

            private function parseComplete (event:Event):void
            {
                resultTA.text = (event.target as XSLTProcessor).output;
            }
        ]]>
    </mx:Script>

    <mx:HTTPService id="xmlLoader"
        url="model.xml"
        resultFormat="e4x"
        result="resultHandler ()"/>

    <mx:TextArea id="resultTA"
        width="100%" height="100%"/>
</mx:WindowedApplication>

Aún y tratarse de una aplicación funcional la clase anterior es una prueba de concepto que casi no he probado. La xsl es un poco chorra, pero es la primera que he encontrado en google.

La verdad que se me ocurren bastantes circunstancias en las que una xsl puede simplificar mucho un desarrollo. No sólo tenemos que pensar en las xsls como una herramienta para la capa de presentación, también podemos usarlas para transformar, adaptar o preparar modelos de datos: por ejemplo ordenación de árboles xml, agrupación, etc.