Archive for the ‘ Development ’ Category

Search in array with SQL staments.

For a project that I’m doing, for various reasons I needed to reduce the number of requests being made by SQL.

I realized that the problem lies basically in the number of SQL queries and come to the conclusion that the ideal would be to have the table in memory and make SQL queries in memory.

Browsing the net I found these two classes to do the same, one for javascript and one for php.

JsonSQL

PhpSQL

poMMo Subscribe Class

Some months ago I has make this little class to manage subscriptions from flash to poMMo Newsletter Manager.

I need to update it to AS3. While I am updating it, you can use the as2 version or update by yourself!!.

To install copy the files from:

1
2
3
4
5
/user/processFlash.php ==> poomo directory /user/
/user/subscribeFLash.fla ==> poomo directory /user/
/themes/default/inc/messagesFlash.tpl ==> poomo directory /themes/default/inc/
/themes/default/inc/messagesFlash.tpl ==> poomo directory /themes/default/inc/
/inc/helpers/validateFlash.php ==> poomo directory  /inc/helpers/

As2 example code

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
import com.xperiments.pommo.Pommo;
import com.xperiments.pommo.PommoUserDefinedField;
import com.xperiments.pommo.PommoEvent;

// get Singleton Pommo Instance
var pommo:Pommo = Pommo.getInstance( );

// set url to processFlash.php
pommo.setSubscribeAction('http://www.yoursite.com/pommo/user/processFlash.php' );
// addListener for: "Invalid Email Address"
pommo.addEventListener( PommoEvent.ERROR_INVALID_EMAIL, this );
//addListener for: "Email address already exists. Duplicates are not allowed."
pommo.addEventListener( PommoEvent.ERROR_EMAIL_ALREADY_EXIST, this );
//addListener for: "Error adding subscriber! Please contact the administrator."
pommo.addEventListener( PommoEvent.ERROR_SERVER_ERROR, this );
//addListener for: "Subscription request received."
pommo.addEventListener( PommoEvent.ERROR_REQUEST_RECEIVED, this );
//addListener for: "Welcome Message."
pommo.addEventListener( PommoEvent.ERROR_WELCOME_MESSAGE, this );
//addListener for: "Send mail Failed"
pommo.addEventListener( PommoEvent.ERROR_SENDING_MAIL, this );
// addListener for: "User Field Error"
pommo.addEventListener( PommoEvent.ERROR_USER_FIELD, this );

function onPommoInvalidEmail( evnt:PommoEvent ){ trace( "[ ERROR ] Invalid Email" ) };
function onPommoEmailExist( evnt:PommoEvent ){ trace( "[ ERROR ] Email address already exists. Duplicates are not allowed." ) };
function onPommoServerError( evnt:PommoEvent ){ trace("[ ERROR ] Error adding subscriber! Please contact the administrator." ) };
function onPommoRequestReceived( evnt:PommoEvent ){ trace("[ REQUEST RECEIVED ] "+evnt.message ) };
function onPommoWelcomeMessage( evnt:PommoEvent ){ trace("[ WELCOME ] "+evnt.message ) };
function onPommoSendMailFailed( evnt:PommoEvent ){ trace("[ SEND MAIL FAILED ]") };
function onUserFieldError( evnt:PommoEvent ){ trace("[ USER FIELD ERROR ]"+evnt.errorDesc) };

// to add EXTRA USER FIELDS uncomment this
// var userDefinedField:PommoUserDefinedField = new PommoUserDefinedField( );
// userDefinedField.addField( 'd[2]' , 'English' );

// pommo.subscribe( "test@test.com", userDefinedField );

// add subscriber whitout EXTRA USER FIELDS
pommo.subscribe( "test@test.com");

Download: xpommo

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.