Comunidad de diseño web y desarrollo en internet online

Problema con XML, ya no se que hacer...

Citar            
MensajeEscrito el 18 Abr 2011 02:23 pm
Hola,

Me he confeccionado una clase para cargar XML y hacerle un "parse" para pasar todo el contenido a un array.

Parece funcionar bien y el código está copiado de los ejemplos y tutos habituales sobre como cargar un XML y demás, la he convertido en clase "static" para llamarla directamente sin crear instancia. Tiene muchos trace al final para comprobar que todo está OK, y el array me lo enseña completo sin problemas.

Código ActionScript :

package {
   import flash.events.Event;
   import flash.net.URLRequest;
   import flash.net.URLLoader;
   import flash.display.MovieClip;

   public class XmlLoader {
      private static var fichero:String = "";
      private static var xml:XML;
      private static var i:int;
      private static var longitud:Number = 0;
      private static var xmlArray:Array = new Array();
      private static var esperaAdivinanza:int = 0;
      private static var esperaPizarra:int = 0;
      private static var empiezaSolucion:int = 0;   
      private static var empiezaAdivinanza:int = 0;
      private static var terminaAdivinanza:String = "0";
      private static var empiezaPizarra:int = 0;

      // declaro el 'constructor'
      public function XmlLoader() {
         trace ("no hago nada");
      }
      
      //funcion que llamaré despues pasándole el nombre del fichero
      //y me devolverá el array
      public static function cargaXML(fichero):Array {
         var loader:URLLoader = new URLLoader(new URLRequest(fichero));
         loader.addEventListener(Event.COMPLETE, xmlLoaded);
         return xmlArray;
      }
      
      public static function xmlLoaded(e:Event):void {
            e.target.removeEventListener(Event.COMPLETE, xmlLoaded);
         xml = new XML(e.target.data);
         xml.ignoreWhitespace=true;
         longitud = xml.adivinanza.length();
         esperaAdivinanza = xml.tiempos.tiempo1;
         esperaPizarra = xml.tiempos.tiempo2;
         empiezaSolucion  = xml.tiempos.tiempo3;
         empiezaAdivinanza = (esperaAdivinanza + esperaPizarra);
         terminaAdivinanza = String(esperaPizarra - 1);
         empiezaPizarra = (esperaPizarra - 1);   
         
         xmlArray.push(longitud);
         xmlArray.push(esperaAdivinanza);
         xmlArray.push(esperaPizarra);
         xmlArray.push(empiezaSolucion);
         xmlArray.push(empiezaAdivinanza);
         xmlArray.push(terminaAdivinanza);
         xmlArray.push(empiezaPizarra);
         
         for (i=0; i < longitud ; i++) {
            xmlArray.push(xml.adivinanza[(i)].linea1);
            xmlArray.push(xml.adivinanza[(i)].linea2);
            xmlArray.push(xml.adivinanza[(i)].linea3);
            xmlArray.push(xml.adivinanza[(i)].linea4);
            xmlArray.push(xml.adivinanza[(i)].@solucion);
         }

         trace ("**********************************");
         trace ("* Cargado adivinanzas_config.xml *");
         trace ("**********************************");
         trace ("");
         trace ("Configuración:");
         trace ("");
         trace ("   Tiempo que se muestra la adivinanza a pantalla completa: " + esperaAdivinanza + " segundos.");
         trace ("   Tiempo que se muestra la pizarra: " + esperaPizarra + " segundos.");
         trace ("   Tiempo que se muestra la solución: " + empiezaSolucion + " segundos.");
         trace ("");
         trace ("Fin configuración");
         trace ("");
         trace ("Adivinanzas:");
         trace ("");
         trace ("Hay " + longitud + " adivinanzas.");
         trace ("");
         trace (xmlArray);
         trace ("");
         trace ("***********************************");
         trace ("* OK parse adivinanzas_config.xml *");
         trace ("***********************************");
      }
   }
}


Mi PROBLEMON viene cuando intento llamar esta clase desde, por ejemplo:

Código ActionScript :

package {
   import flash.display.MovieClip;
   import XmlLoader;

   public class Probandoclase extends MovieClip {

      public var longitud:Number = 22;//Por darle un valor cualquiera para ver si lo cambia
      public var nuevoArray:Array = new Array();

      public function Probandoclase():void {
         nuevoArray = XmlLoader.cargaXML("imaxina_datos/adivinanzas_config.xml");
         trace ("Resultado:");
         trace (nuevoArray);
      }
   }
}


No da ningún error peeeero en el output veo:
Resultado:

*************************
* Cargado adivinanzas_config.xml *

Blah, blah, blah, y todo el trace de la clase XmlLoader sale perfecto, pero el array nuevoArray está vacio como puede comprobarse en la línea en blanco que aparece a continuación de 'Resultado:'

Creo que mis problemas vienen de que no entiendo bien el flujo del script, parece como que el evento que se le pone al loader para que haga el parsing una vez terminado de cargar el fichero XML no se ejecuta donde yo pienso y el flujo principal del script continua y cuando devuelve el array desde la llamada a la clase todavía no está cargado o algo así... Me cuesta explicarlo. Por muchas vueltas que le doy y cientos de pruebas y diferentes versiones, siempre me encuentro con lo mismo, el array continua vacio.

Alguna idea?

Lo que me gustaría es poder llamar a una clase que me cargue un XML de unas características determinadas (no voy a reutilizar la clase para otros XMLs) y lo pase a uno o varios arrays para luego poder disponer de el/ellos durante el resto del script. Parece fácil, pero me está acabando con la paciencia hasta el punto de postear en un foro, cosa que sólo hago cuando ya me he leído todo lo que he encontrado :-(

Agradezco sus comentarios de antemano.

Un saludo

JParis

Por jparis

13 de clabLevel



 

España

firefox
Citar            
MensajeEscrito el 18 Abr 2011 04:14 pm
No estoy muy de acuerdo con uar una clase estatica para un parser de XML que no se va a reutilizar ... pero en fin. Tu error es porque no esperas a que termine de cargar y parsear el XML, lo cual constituye una operación asincrónica. Debes generar un evento desde tu clase XMLLoader que avise que ha terminado la carga y el parseo, desde tu otra clase escuchas el evento y accedes al array

Jorge

Por solisarg

BOFH

13669 de clabLevel

4 tutoriales
5 articulos

Genero:Masculino   Bastard Operators From Hell Premio_Secretos

Argentina

firefox
Citar            
MensajeEscrito el 18 Abr 2011 07:53 pm
OK, entiendo (más o menos).

Te cuento. Yo no soy programador ni pretendo serlo en ningún momento futuro, me dedico a la ingeniería audiovisual, televisiones, centros de retransmisión, unidades móviles. etc. El caso es que, por motivos que no vienen al caso, me veo metido en este "fregado", de sacar para adelante una aplicación que, aunque sencilla, para mí es un mundo de problemas ya que NUNCA antes programé AS3 ni Flash.

Inicialmente la hice en Flash, con un poquito de AS3 en cada frame para controlar el flujo y valió como prueba, pero necesito hacerla más "profesional" y aligerarla en lo posible, así como sacar fuera (en una "document class", creo que así se llama) todo lo posible para que sea fácil modificar o añadir cosas.

Es una aplicación que muestra una adivinanza en pantalla, te da un tiempo para leerla, pasa a una "pizarra" donde puedes dibujar la que piensas es la solución (esta parte la saqué de un ejemplo libre que encontré) y luego de un tiempo, que se puede ver en un contador regresivo, muestra la solución en forma de un gráfico PNG y vuelta a empezar con otra adivinanza.

Como ves es sencillo, tengo un XML con las adivinanzas y las soluciones así como unos campos de configuración para los tiempos de cada apartado y, usando el timeline como te decía, funciona OK (aún no me creo que lo consiguiese dado el tiempo del que disponía para hacerlo).

Dicho esto, hice una clase estática porque en una de los cientos de pruebas que hice me funcionó bien y siempre tenía problemas con las clases "normales", así que me decanté por ahí porque necesitaba tirar para adelante, pero si me dices que es mejor hacerla "normal", lo intento a ver a dónde llego.

Entiendo lo que me dices, pero invluso intenté poner un bucle de retardo para darle tiempo al evento a completarse y esperar unos 10 segundos antes de acceder al array, pero el resultado es el mismo y eso es lo que me mata porque no lo comprendo.

Podrías ayudarme con esto e indicarme cómo se genera ese evento y cómo lo "escucho" desde la clase "principal"?

Te voy a mandar un privado con un comentario a mayores.

MUCHAS gracias

Por jparis

13 de clabLevel



 

España

firefox
Citar            
MensajeEscrito el 18 Abr 2011 08:07 pm
El evento

public class XmlLoader extends EventDispatcher{

(...)

al final del metodo xmlLoaded

dispatchEvent(new Event(Event.COMPLETE));

En la clase que escucha

XmlLoader.addEventListener(Event.COMPLETE, miFuncion)

En miFuncion procesas la info del XmlLoader

Jorge

Por solisarg

BOFH

13669 de clabLevel

4 tutoriales
5 articulos

Genero:Masculino   Bastard Operators From Hell Premio_Secretos

Argentina

firefox
Citar            
MensajeEscrito el 18 Abr 2011 11:48 pm
En mi primer intento he colocado lo que me has dicho, el dispatchEvent al final de los trace del xmlLoaded y el la clase que llama a esta el addEventListener después de nuevoArray = XmlLoader... y he convertido los trace en una función que es la que llamo desde el listener.

El resultado es que el output indica:
"ReferenceError: Error #1065: No se ha definido la variable Event.
at Probandoclase()"
En lugar de los habituales "resultado: " y "" en las dos primeras líneas,
luego viene la salida de los traces del xmlLoaded sin problema y al final:
"ReferenceError: Error #1065: No se ha definido la variable dispatchEvent.
at XmlLoader$/xmlLoaded()
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at flash.net::URLLoader/onComplete()"

En fin, ya que estamos, a la par de solucionar esto, ¿no hay una manera de leer un XML sin usar eventos, vamos cargarlo, parsearlo y listo? Curioso que es uno...

Paris

Por jparis

13 de clabLevel



 

España

firefox
Citar            
MensajeEscrito el 19 Abr 2011 12:41 am
Recuerda agregar

import flash.events.Event

Para que reconozca la clase Event. Si usas clases, tienes que usar eventos .... aunque en General en AS3 siempre tendrás que usar eventos

Jorge

Por solisarg

BOFH

13669 de clabLevel

4 tutoriales
5 articulos

Genero:Masculino   Bastard Operators From Hell Premio_Secretos

Argentina

firefox
Citar            
MensajeEscrito el 19 Abr 2011 08:09 am
OK, la clase ya estaba importada en los dos scripts, con lo que sigo en el mismo punto...

Hmmmm, una cosa más, podrías explicarme cómo va el flujo de ejecución de esto, para que me entere bien de por qué no funciona bien sin este añadido, ya me dijiste que es asíncrono y tal y eso lo entiendo e, incluso, lo suponía de antemano, pero lo que no entiendo es que aún añadiendo una espera bien larga, para que le de tiempo a cargar el fichero, parsearlo 100 veces y tomarse un café, no funcione.

Por otra parte comentarte que este error que ha ocurrido aún importando la clase es lo que me pasaba siempre con todas las pruebas que hice con clases, de ahí que me pasé o lo de estática porque, a la desesperada, es la única que me funcionaba bien, sin quejarse. Es otra cosa que tampoco acabo de entender, esto parece una guerra en vez de un script, la máquina contra mí :-)))))))))))

Por jparis

13 de clabLevel



 

España

firefox
Citar            
MensajeEscrito el 19 Abr 2011 10:04 am
Mmm, y has puesto esto al declarar la clase?

Código ActionScript :

public class XmlLoader extends EventDispatcher


Lo de esperar N tiempo a ver si ha cargado o no es un método de adivinación poco adecuado para cualquier aplicación

Jorge

Por solisarg

BOFH

13669 de clabLevel

4 tutoriales
5 articulos

Genero:Masculino   Bastard Operators From Hell Premio_Secretos

Argentina

firefox
Citar            
MensajeEscrito el 19 Abr 2011 11:29 am
Si, por supuesto tiene esa linea, ahora no estoy en casa, cuando llegue posteo los dos script en su estado actual, por si sirve de algo.

Por jparis

13 de clabLevel



 

España

safari
Citar            
MensajeEscrito el 20 Abr 2011 12:25 am
Tarde pero llegué...

La clase que carga y parsea el XML:

Código ActionScript :

package {
        
   import flash.events.*;
   import flash.net.URLRequest;
   import flash.net.URLLoader;
   import flash.display.MovieClip;

   public class XmlLoader extends EventDispatcher {
 
      private static var fichero:String = "";
      private static var xml:XML;
      private static var i:int;
      private static var longitud:Number = 0;
      private static var xmlArray:Array = new Array();      
      private static var esperaAdivinanza:int = 0;
      private static var esperaPizarra:int = 0;
      private static var empiezaSolucion:int = 0;
      private static var empiezaAdivinanza:int = 0;
      private static var terminaAdivinanza:String = "0";
      private static var empiezaPizarra:int = 0;

      // declaro el 'constructor'
      public function XmlLoader() {
         trace ("no hago nada");
      }
      
      //funcion que llamaré despues pasándole el nombre del fichero
      public static function cargaXML(fichero):Array {
         var loader:URLLoader = new URLLoader(new URLRequest(fichero));
         loader.addEventListener(Event.COMPLETE, xmlLoaded);
         return xmlArray;
      }
      
      // preparo el objeto xml y le hago el "parsing"
      public static function xmlLoaded(e:Event):void {
         
            e.target.removeEventListener(Event.COMPLETE, xmlLoaded);
         xml = new XML(e.target.data);
         xml.ignoreWhitespace=true;
         longitud = xml.adivinanza.length();
         esperaAdivinanza = xml.tiempos.tiempo1
         esperaPizarra = xml.tiempos.tiempo2
         empiezaSolucion  = xml.tiempos.tiempo3
         empiezaAdivinanza = (esperaAdivinanza + esperaPizarra);
         terminaAdivinanza = String(esperaPizarra - 1);
         empiezaPizarra = (esperaPizarra - 1);
         
         xmlArray.push(longitud);
         xmlArray.push(esperaAdivinanza);
         xmlArray.push(esperaPizarra);
         xmlArray.push(empiezaSolucion);
         xmlArray.push(empiezaAdivinanza);
         xmlArray.push(terminaAdivinanza);
         xmlArray.push(empiezaPizarra);
         
         for (i=0; i < longitud ; i++) {
            xmlArray.push(xml.adivinanza[(i)].linea1);
            xmlArray.push(xml.adivinanza[(i)].linea2);
            xmlArray.push(xml.adivinanza[(i)].linea3);
            xmlArray.push(xml.adivinanza[(i)].linea4);
            xmlArray.push(xml.adivinanza[(i)].@solucion);
         }

         trace ("**********************************");
         trace ("* Cargado adivinanzas_config.xml *");
         trace ("**********************************");
         trace ("");
         trace ("Configuración:");
         trace ("");
         trace ("   Tiempo que se muestra la adivinanza a pantalla completa: " + esperaAdivinanza + " segundos.");
         trace ("   Tiempo que se muestra la pizarra: " + esperaPizarra + " segundos.");
         trace ("   Tiempo que se muestra la solución: " + empiezaSolucion + " segundos.");
         trace ("");
         trace ("Fin configuración");
         trace ("");
         trace ("Adivinanzas:");
         trace ("");
         trace ("Hay " + longitud + " adivinanzas.");
         trace ("");
         trace (xmlArray);
         trace ("");
         trace ("***********************************");
         trace ("* OK parse adivinanzas_config.xml *");
         trace ("***********************************");
         dispatchEvent(new Event(Event.COMPLETE));
      }
   }
}


Y la Document Class que tengo hecha para probar si la anterior funciona bien:

Código ActionScript :

package {

   import flash.display.MovieClip;
   import flash.events.*;
   import XmlLoader;

   public class Probandoclase extends MovieClip {

      public var longitud:Number = 22;
      public var nuevoArray:Array = new Array();

      public function Probandoclase():void {
         nuevoArray = XmlLoader.cargaXML("imaxina_datos/adivinanzas_config.xml");
         XmlLoader.addEventListener(Event.COMPLETE, resultado);
      }
      public function resultado():void {
         trace ("hola");
         trace (nuevoArray);
      }

   }
}


Hay un cambio y es que había escrito mal el 'import flash.events.*' en esta última class, con lo que no se cargaba, en cualquier caso el problema persiste, salvo que ahora las dos primeras líneas rezan así:

TypeError: Error #1006: addEventListener no es una función.
at Probandoclase()

Uffff

Por jparis

13 de clabLevel



 

España

firefox
Citar            
MensajeEscrito el 20 Abr 2011 02:06 pm
En este momento nuevoArray se define como undefined:

nuevoArray = XmlLoader.cargaXML("imaxina_datos/adivinanzas_config.xml");

Lo que tienes que hacer es un getter que devuelva nuevoArray, al que llamas en el evento Complete. Luego el error no tiene mucho sentido, ya que la clase MovieClip tiene el metodo y tu clase extiende de MovieClip

Jorge

Por solisarg

BOFH

13669 de clabLevel

4 tutoriales
5 articulos

Genero:Masculino   Bastard Operators From Hell Premio_Secretos

Argentina

firefox
Citar            
MensajeEscrito el 27 Abr 2011 12:47 am
Hola Jorge,

Tengo el tema más o menos encauzado, me he comprado un libro sobre AS3 de O'Really (tengo muchos otros de esta editorial y son realmente buenos, se los recomeindo a cualquiera) y ha despejado muchas dudas, lo cierto es que debería de haber empezado por ahí...

En cualquier caso sigo teniendo una duda existencial sobre como se desarrolla el flujo del programa cuando hay un evento por medio.

He rehecho todo para que sea una class "normal", no estática. la llamo y funciona OK, incluso he hecho de forma que el array dichoso se declara en el Document Class y luego el class del XML lo utiliza, o sea, que creo el array en el flujo "main" y luego cuando instancio la class del xml parseo el xml cargando el resultado en el array del "main" y sigo igual que al principio, por muy largo que sea el flujo del "main" no tengo los valores cargados en el array hasta que termina el flujo del "main" y no lo entiendo.

No se supone que cuando pones un listener es como una interrupción en código máquina, que cuando ocurre ese "evento" procesamos la interrupción a parte o en paralelo. Porque no entiendo porque no tengo ejecutado el loader ahsta que termine el flujo principal, realmente no es que sea "asíncrono" como bien dices, es que simplemente pasa del evento hasta que termina con lo que está haciendo y eso es lo que no acabo de entener.

Por otra parte me propones generar un nuevo evento para avisar de que ya está listo el parseo del XML, pero es la sardina que se muerde la cola, por lo que veo el evento de cargar el XML no se ejecuta hata que termina el flujo principal desde el que lo llamé, con lo que nunca voy a tener ese aviso antes de que termine la ejecución del flujo principal, por lo menos eso es lo que parece viendo el output de la consola.

No se si me he explicado bien, pero te pongo un ejemplo para ayudar:

He probado a utilizar el típico "semáforo", en este caso uso "longitud" que la pongo a cero cuando la declaro (en el código actual la declaro en el document class y la uso desde el XmlLoader class) y hago un

Código ActionScript :

while (longitud == 0) {
          trace ("longitud sigue en 0");
}


Pensando en ques esto detendría el flujo del programa mientras se cargaba el XML, se parseba y demás, ya que en ese proceso se actualiza "longitud" a su valor de acuerdo al XML, pero el compilador (no se si el compilador o en ejecución, pero creo que lo primero) se queda "colgado" esperando toda la vida sin resultado alguno... (Salvo que me deja el Flash tirado)

¿Serias tan amable de explicarme esto de forma racional? Porque no encuentro ningún libro ni documento que lo explique de forma que lo entienda. Entiendo lo que es un evento (o eso me parece), entiendo que lo que hago es una operación asíncrona (y soy muy consciente de lo que significa asíncrono), pero no entiendo como se relaciona un evento con el flujo del programa.

Gracias y perdón por el tostón :-(

Por jparis

13 de clabLevel



 

España

firefox
Citar            
MensajeEscrito el 27 Abr 2011 01:52 pm
Me perdi un poco de este hilo y soy un poco vago para leer. Si entiendes lo que es operacion asincrona y lo que es evento, pues básicamente se ejecuta el callback cuando se genera el evento. La ejecución de código es por fotograma, y si tienes 100 líneas en un fotograma, se ejecutan en milisegundos, muchísimo mas rápido de lo que puede tardar en cargarse y parsearse un XML, por eso generalmente todo lo que sea dinámico se ejecutará usualmente al final, y no se pueden hacer desiciones sobre lo que tiene que pasar con eso en el código principal, sino en el callback que para eso existe

Jorge

Por solisarg

BOFH

13669 de clabLevel

4 tutoriales
5 articulos

Genero:Masculino   Bastard Operators From Hell Premio_Secretos

Argentina

firefox

 

Cristalab BabyBlue v4 + V4 © 2011 Cristalab
Powered by ClabEngines v4, HTML5, love and ponies.