El desafío implica que seamos capaces de mostrar los datos dinámicamente mediante programación en el lenguaje de scripting específico del Flash: ActionScript, logrando que la película funcione correctamente cualquiera que sea la cantidad de datos que el XML contenga, situación ideal para sitios web con actualización frecuente de contenidos.

Presentación del archivo XML y algunas nociones sobre Arrays

En la primera parte de este tutorial desarrollamos una página ASP que, luego de conectarse a una base de datos Access, recogía los datos correspondientes a los representantes comerciales de una empresa ficticia y los volvía a grabar en formato XML respetando la estructura jerárquica original.

Esta jerarquía implicaba que los Representantes estaban divididos según su País de residencia y que a su vez los Países estaban agrupados en Áreas Geográficas.
Independientemente de su origen (generado a partir de una base de datos o tipeado directamente en un editor de texto) el archivo XML resultante tiene la estructura que se muestra en la siguiente imagen:

Nota: no se muestran los datos, sólo la arquitectura general del archivo para el utópico caso de un Area con un solo País y dos Representantes. Desarrollaremos el resto del trabajo dentro del Flash, desde donde cargaremos el contenido del archivo XML en una serie de Arrays (o Matrices) que a su vez utilizaremos para mostrar dinámicamente los datos.

En este contexto, dinámicamente significa que crearemos en tiempo de ejecución los movieclips que contendrán el texto que queremos mostrar. Para tratar de que la cosa sea un poco más clara comentaremos primero cuáles serán los Arrays que utilizaremos:

  • Un Array de Areas Geográficas, cuyos elementos serán las Areas que se encuentren en el XML. En el caso del ejemplo será:
    areas = ["América del Sur", "América Central y Caribe", "América del Norte", "Europa"].
  • Un Array por cada Area Geográfica, cuyos elementos serán los Países que están incluídos en esa Area.
    Por ejemplo:
    América del Sur = ["Argentina", "Brasil", "Chile", "Uruguay"]
  • Un Array por cada País, cuyos elementos serán los datos de cada uno de los Reresentantes de ese País.
    Este Array es peculiar ya que sus elementos son en realidad Arrays Asociativos, que guardan pares dato:"valor", y son especialmente útiles para los datos personales de los Representantes.
    Veamos el ejemplo simplificado del Array Argentina:
    Argentina = ["elem1", "elem2"] tiene dos asociativos:
    elem1 = {ciudad:"Buenos Aires",nombre:"Alejandro",apellido:"González",…etc.}
    elem2 = {ciudad:"Córdoba",nombre:"Mabel",apellido:"Lucero",…etc.}
    Para acceder a sus valores:
    Argentina [0].nombre = Alejandro
    Argentina[1].ciudad = Córdoba

Trabajando en Flash con ActionScript

Ya con el Flash, abrimos una nueva película que denominaremos representantes.fla.
Denominaremos la primera capa como ‘actionscript’ y allí colocaremos todo el código utilizando el Panel de Acciones (F9 para abrir).
En el fotograma 1 colocaremos primero el código encargado de:

  • Cargar los datos del XML dentro de un Objeto XML del Flash
  • Construir el esquema de Arrays que analizamos un poco más arriba

Utilizaremos tres bucles for anidados (Áreas, Países de cada Área y Representantes de cada País). Debemos recordar que desconocemos de antemano el nombre que tomarán la mayoría de los Arrays (dependerán de los datos contenidos en el XML), por lo que deberán declararse como _root[nombre_variable] (sin punto).

Cargar datos y armar Arrays:

// Nos aseguramos que se muestren bien los acentos

System.useCodepage = true; // Creamos el objeto que guardará los datos del archivo XML represXML = new XML(); represXML.ignoreWhite = true; //Cargamos el archivo XML en el objeto recién creado represXML.load("../xml/representantes.xml"); // Cuando termina de cargar lo mandamos a organizar para poder mostrar los datos represXML.onLoad = organizarXML; stop(); // Esta es la función encargada de armar los Arrays a partir de los datos function organizarXML() { // Array para las Areas Geográficas areas = new Array(); // Primer bucle para buscar Areas revisando todos los primeros nodos // ejemplo: América del Sur, América Central, etc. for (yy=0; yy<represXML.firstChild.childNodes.length; yy++) { // Agregar el nombre del Area (guardado como Atributo) al Array de Areas Geográficas areas.push(represXML.firstChild.childNodes[yy].attributes.nombre); // Crear un Array con el nombre de cada una de las Áreas encontradas _root[represXML.firstChild.childNodes[yy].attributes.nombre] = new Array(); // Segundo bucle para buscar el nombre de los Países (atributo) de cada Area // ejemplo: Argentina, Brasil, etc. for (aa=0; aa<represXML.firstChild.childNodes[yy].childNodes.length; aa++) { // Agregar el nombre del País al Array del Area a la que pertenece _root[represXML.firstChild.childNodes[yy].attributes.nombre].push(represXML.firstChild.childNodes[yy].childNodes[aa].attributes.nombre); // Utilizar el nombre de cada País (ejemplo: Argentina) para crear un nuevo Array // donde se van a guardar los datos de los Representantes que pertenecen a ese país _root[represXML.firstChild.childNodes[yy].childNodes[aa].attributes.nombre] = new Array(); // Tercer bucle para entrar a cada Representante y leer sus atributos for (bb=0; bb<represXML.firstChild.childNodes[yy].childNodes[aa].childNodes.length; bb++) { // Crear un Objeto para guardar los datos de cada Representante como si fueran propiedades del Objeto (array asociativo con pares dato:"valor" ) repre = new Object(); repre.ciudad = represXML.firstChild.childNodes[yy].childNodes[aa].childNodes[bb].attributes.ciudad; repre.nombre = represXML.firstChild.childNodes[yy].childNodes[aa].childNodes[bb].attributes.nombre; repre.apellido = represXML.firstChild.childNodes[yy].childNodes[aa].childNodes[bb].attributes.apellido; repre.telefono = represXML.firstChild.childNodes[yy].childNodes[aa].childNodes[bb].attributes.telefono; repre.email = represXML.firstChild.childNodes[yy].childNodes[aa].childNodes[bb].attributes.email; // Agrego el Objeto (datos representante) al Array del país _root[represXML.firstChild.childNodes[yy].childNodes[aa].attributes.nombre].push(repre); // Elimino el Objeto delete repre; } } } // Mandamos los datos ya organizados a que se muestren (la función está más abajo) mostrarDatos(); }  

En este punto tenemos nuestros datos poblando una serie de Arrays y solo nos resta mostrarlos ordenadamente. Mostrar los datos dinámicamente.

Dado que disponemos de tres tipos de datos: Area, País y los datos del Representante, agregaremos a la Biblioteca tres movieclips. Cada movieclip tendrá como contenido cajas de texto dinámico que mostrarán el contenido de las siguientes variables:

  • mc_areas (identificador para linkage: mc_areas): tx_area
  • mc_paises (identificador para linkage: mc_paises): tx_pais
  • mc_repres (identificador para linkage: mc_repres): tx_ciudad, tx_nom_ape, tx_telefono y tx_email

Por ejemplo, para el mc_areas:

Como estos movieclips se agregarán al escenario dinámicamente debemos indicarle al Flash que los exporte para ser utilizados en tiempo de ejecución. Esto lo realizamos indicando un identificador para Linkage, que por comodidad establecemos igual al nombre del movieclip.

Para establecer el identificador se debe pulsar con el botón derecho del mouse sobre el movieclip en la Biblioteca y seleccionar Linkage, en el menú emergente. Básicamente lo que haremos será crear un movieclip vacío que denominaremos "contenedor", que contendrá la lista en sí, utilizando createEmptyMovieClip(nombre de instancia, nivel).

De un modo similar a lo que hicimos antes, utilizaremos tres bucles for anidados para recorrer nuestros Arrays e iremos sucesivamente agregando a "contenedor" instancias de los movieclips que tenemos en la Biblioteca mediante attachMovie(id. de linkage, nombre de instancia, nivel).

Como la lista resultará extensa (tendrá un desarrollo vertical mayor que el alto de la película) crearemos otro movieclip vacío (denominado "mc_msk") y dentro dibujaremos con ActionScript un rectángulo del tamaño apropiado para oficiar de "ventana".

Colocando a "mc_msk" como máscara de "contenedor" lograremos ocultar el sobrante de la lista y solo restará hacer que "contenedor" se deslice hacia arriba y hacia abajo dentro de ciertos límites para que todos los Representantes resultes visibles.

El siguiente código continúa al anterior:

function mostrarDatos() {
 // Creamos un mc vacío para encapsular la lista de Representantes
 // y lo posicionamos en el escenario principal
 _root.createEmptyMovieClip("contenedor", 300);
 _root.contenedor._x = 10;
 _root.contenedor._y = 50;
 // Construímos la lista
 intContaPaises = 0;
 intContaRepres = 0;
 intPosicion = 0;
 intSeparar = 50;
 // Para cada una de las Areas
 for (aa=0; aa<areas.length; aa++) {
 _root.contenedor.attachMovie("mc_areas", "mc_areas"+aa, aa);
 _root.contenedor["mc_areas"+aa]._y = (intPosicion * intSeparar);
 _root.contenedor["mc_areas"+aa]._x = 25;
 _root.contenedor["mc_areas"+aa].tx_area = areas[aa];
 intPosicion++;
 // Para cada uno de los Países del Area
 for (bb=0; bb<_root[areas[aa]].length; bb++) {
 _root.contenedor.attachMovie("mc_paises", "mc_paises"+intContaPaises, 100+intContaPaises);
 _root.contenedor["mc_paises"+intContaPaises]._y = (intPosicion * intSeparar);
 _root.contenedor["mc_paises"+intContaPaises]._x = 45;
 _root.contenedor["mc_paises"+intContaPaises].tx_pais = _root[areas[aa]][bb];
 intPosicion++;
 // Para cada Representante de cada País
 for (cc=0; cc<_root[_root[areas[aa]][bb]].length; cc++) {
 _root.contenedor.attachMovie("mc_repres", "mc_repres"+intContaRepres, 200+intContaRepres);
 _root.contenedor["mc_repres"+intContaRepres]._y =(intPosicion * intSeparar);
 _root.contenedor["mc_repres"+intContaRepres]._x = 55;
 _root.contenedor["mc_repres"+intContaRepres].tx_ciudad = _root[_root[areas[aa]][bb]][cc].ciudad;
 _root.contenedor["mc_repres"+intContaRepres].tx_nom_ape = _root[_root[areas[aa]][bb]][cc].nombre + " " + _root[_root[areas[aa]][bb]][cc].apellido;
 _root.contenedor["mc_repres"+intContaRepres].tx_telefono = _root[_root[areas[aa]][bb]][cc].telefono;
 _root.contenedor["mc_repres"+intContaRepres].tx_email = _root[_root[areas[aa]][bb]][cc].email;
 intPosicion++;
 intContaRepres++;
 }
 intContaPaises++;
 }
 }
 // Creamos un nuevo mc en el que dibujamos un rectángulo con las dimensiones
 // apropiadas para el tamaño de nuestra película
 _root.createEmptyMovieClip("mc_msk", 301);
 mc_msk._x = 10;
 mc_msk._y = 50;
 // Dibujamos el rectángulo (en este caso de 530px de ancho por 350px de alto)
 // No importan los colores de trazo y relleno porque no se verá, lo utilizaremos como máscara.
 with (mc_msk) {
 beginFill(0xff0000,50);
 lineStyle(1,0x00ff00,100);
 lineTo(530,0);
 lineTo(530,350);
 lineTo(0,350);
 lineTo(0,0);
 endFill();
 }
 // Enmascaramos el listado con el recuadro que acabamos de dibujar y LISTO! ;-)
 _root.contenedor.setMask(mc_msk);
 }

Como último detalle ponemos el código de los botones que manejan el scroll de "contenedor".

Botón Subir:

    on (release) {
    if (_root.contenedor._y < _root.mc_msk._y) {
    _root.contenedor._y += _root.intSeparar;
    }
    }

Botón Bajar:

on (release) {
  if (_root.contenedor._y > _root.mc_msk._height - _root.contenedor._height) {
  _root.contenedor._y -= _root.intSeparar;
  }
  }

Al ejecutar la película terminada se obtendrá un resultado similar al de la siguiente imagen, dependiendo de los detalles accesorios de presentación que se agreguen:

Este tutorial fue publicado originalmente en rakidwam.com.ar por Fernando Campaña.