Desarrollo de aplicaciones web
Licencia Creative Commons
Jeisson Hidalgo-Céspedes
Versión 0.5.0. 2016-Ago-13.

Tabla de contenidos

Introducción a la tecnología web

De todas las aplicaciones que se han construido sobre Internet, la World Wide Web (WWW o simplemente web) ha sido la más popular, tanto que, muchas personas cuando escuchan el término "Internet" realmente imaginan la web. La web puede definirse como un sistema de documentos de hipertexto interrelacionados entre sí y accesibles a través de Internet. Se dice que son documentos de hipertexto o hipermedios, por su capacidad de contener diferentes medios de comunicación: texto, imágenes, sonido, vídeo, enlaces, etc.

La popularidad de la web puede adjudicarse a su facilidad de uso y por ser el más exitoso de los sistemas distribuidos en la actualidad. Los documentos se almacenan en computadoras distintas, con sistemas operativos diversos, generados de fuentes heterogéneas, pero esto es transparente para el usuario. De hecho, para el usuario todos los documentos del mundo parecen ser parte de un único sistema, lo cual es fundamento de lo que se define como un sistema distribuido.

10 pts

Para responder a los ejercicios de este material, cree un repositorio de control de versiones. Por ejemplo, un repositorio privado de git en BitBucket (sugerencia nombre su repositorio de la forma cursoweb_nombre_estudiante). Invite al profesor como colaborador del repositorio (usuario del profesor en BitBucket: jeissonh). Clone el repositorio en su máquina local. Cree una carpeta por cada uno de los capítulos de este material, algo como:

intro/
xml/
html/
css/
js/
php/

Cada vez que resuelva un ejercicio, cree una subcarpeta dentro del capítulo al que pertenece. Utilice como nombre de la carpeta del ejercicio, el identificador del ejercicio. Por ejemplo, use web_vs_desktop y no Ejercicio 1.2, ya que los números de ejercicios cambian conforme se agregan o mueven éstos por el documento.

5 pts

¿Por qué hay tanto interés en crear aplicaciones web en lugar de aplicaciones de escritorio? Compare las ventajas y desventajas de cada una. Escriba sus percepciones en un documento de texto, en una carpeta intro/web_vs_desktop.

10 pts

Represente los eventos que considere más relevantes de la historia de la web (siguiente sección) en una línea de tiempo. Dibuje la línea de tiempo en una imagen vectorial en formato Scalable Vector Graphics (SVG). Puede utilizar el software libre Inkscape. Guarde su imagen en control de versiones, en la carpeta intro/history_timeline.

Historia

La web fue conceptualizada en un artículo de 1989 de Tim Berners-Lee, quien se convertiría en uno de sus grandes líderes. A finales de 1990, Berners-Lee desarrolló el Protocolo de transferencia de hipertexto (HTTP, HyperText Transfer Protocol), el primer servidor web llamado CERN-httpd; el primer navegador llamado WorldWideWeb, que también era un editor web; el lenguaje de marcado de hipertexto (HTML, HyperText Markup Language); y las primeras páginas web que hablaban sobre el proyecto mismo.

La aparición pública de la web fue en 1991, cuando Berners-Lee describió el proyecto en un grupo de noticias (Usenet newsgroup). Había nacido un mecanismo eficiente que permite a cualquiera ser autor, compartir material de interés al mundo, y hacer referencia al existente a través de hiper-enlaces.

La difusión de la web fue lenta. Inicialmente fue adoptada por universidades y grupos científicos. Los documentos web eran muy sencillos y la mayoría de navegadores corrían en modo texto, unos pocos eran gráficos como el escrito por Berners-Lee en una NeXT. Desde 1992 muchos navegadores se construyeron, pero el más influyente de todos fue Mosaic.

En 1993 el National Center for Supercomputing Applications (NCSA) de la University of Illinois en Urbana-Champaign (UIUC), introdujo el navegador gráfico Mosaic, como un proyecto de investigación. NCSA licitaba su código fuente a otras compañías para que crearan sus propios navegadores, incluso comerciales. Tras de graduarse, el líder del proyecto Mosaic, Marc Andreessen, fundaría la compañía Netscape en 1994, para comercializar su navegador Netscape Navigator, el cual corría transparentemente entre diversos sistemas operativos. Era gratis para uso no comercial, por lo que se convirtió en el navegador más usado del mundo.

En 1994 Berners-Lee funda el World Wide Web Consortium (W3C) en el Instituto Tecnológico de Massachusetts (MIT, Massachusetts Institute of Technology), apoyado por varias instituciones y empresas con el fin de crear estándares y recomendaciones para mejorar la calidad de la web.

La primera guerra de navegadores

En 1995 Microsoft incluye Internet Explorer 1.0 en Windows 95, basado en código fuente de NCSA Mosaic. La versión 2.0 fue gratuita incluso para uso comercial. Lentamente Internet Explorer va tomando popularidad y mercado de Netscape, lo que generaría la primera guerra de navegadores.

Los ataques entre estos dos navegadores consistían en la inclusión de funcionalidades novedosas para atraer tanto usuarios como autores de sitios web. Por ejemplo, Netscape desarrolló JavaScript a finales de 1995, que un año más tarde sería imitado por el JScript de Microsoft, en la versión 3 de Internet Explorer. En esa versión particular, Microsoft incluyó una parcial implementación de las hojas de estilo en cascada (CSS, Cascading Style Sheets) sugeridas por el W3C pero aún no estandarizadas.

En 1997 Netscape fusionó su Netscape Navigator con otro conjunto de programas para correo electrónico, composición web, calendario, etc. Al suite se le llamó Netscape Communicator, nombre que serviría para confusiones. Microsoft integró Internet Explorer 4 con Windows y desalentó desde el sistema operativo el uso de cualquier otro navegador. Netscape no compitió contra esto, ni tenía sentido. Desde 1998 el 80% del mercado que tenía Netscape pasó a sumar el 96% que tenía Internet Explorer 5 en el 2002. La guerra de los navegadores había finalizado y también el rápido tren de innovaciones; tan evidente que Microsoft no volvería a hacer cambios significativos en su navegador desde el 2001 al 2006.

A inicios de 1998 Netscape libera el código fuente de Netscape Communicator 4.0 en el proyecto Mozilla. La comunidad descartaría luego dicho código debido a su complejidad, poca modularización, al gran volumen de pulgas y otros inconvenientes; y empezó la elaboración de un nuevo motor de navegador (web browser engine) hecho desde cero, al cual se le llamó, Gecko, y sería el motor de "rendering" de Firefox y el nuevo Netscape Communicator, que finalmente sería descontinuado a inicios del 2008.

El proceso de estandarización

La guerra de navegadores (aproximadamente de 1995 a 1998) también tuvo consecuencias muy negativas. Ambos, Netscape Navigator e Internet Explorer, ofrecían características novedosas incompatibles entre sí, es decir, dialectos de HTML distintos que provocaron que los autores de millones de páginas tuvieran que escoger por uno o el otro. Era común ver imágenes indicando que el sitio se veía mejor con un navegador particular, incluso hasta de una versión específica.

Mientras tanto el proceso de estandarización avanzaba lentamente. En junio de 1993 el Consorcio Web (W3C) propone varios borradores de estandarización y en noviembre de 1995, la Internet Engineering Task Force (IETF) aprueba el HTML 2.0 que luego se convertiría en estándar internacional en 1997. El W3C propone HTML 3.0 en abril de 1995 pero la IETF no realiza ninguna acción. Los navegadores tomarán luego ideas de estas iniciativas en proceso y las implementarán a su manera para atraer usuarios.

A inicios de 1997 la IETF traslada la responsabilidad de estandarización al W3C, quien publicaría recomendaciones con una eficiencia mayor. Se publica el HTML 3.2 adoptando etiquetas y atributos de marcado visual de Netscape (como b y font). A final del mismo año, el W3C presenta el trabajo de estandarización más notorio hasta la fecha, conocido como HTML 4.0. Un esfuerzo que considera las extensiones derivadas de la guerra de navegadores y las raíces del HTML. En ella, las etiquetas de marcado visual serían desaprobadas ("deprecated") en favor de CSS; pero su uso se había difundido tanto que el W3C decidió generar tres variaciones del HTML 4.0:

  • HTML 4.0 Strict. Prohíbe elementos "deprecated".
  • HTML 4.0 Transitional. Permite elementos "deprecated".
  • HTML 4.0 Frameset. Permite construir páginas basadas en "frames", con los elementos frameset y frame.

Dos años después, a finales de 1999, se le haría una ligera modificación al estándar HTML 4.01, cuya variación estricta (HTML 4.01 Strict) sería adoptado como estándar internacional (ISO/EIC 15445:2000), suplantando la versión 2.0 de 1997. Tras ello, el trabajo de estandarización dejaría de lado al HTML para concentrarse en el XHTML.

En febrero de 1998 el W3C publicó el estándar XML (Extensible Markup Language). En enero de 2000 se reformuló HTML 4.01 como una aplicación XML en lo que conoce como XHTML 1.0. Una actualización XHTML 1.1 se emitió como recomendación en mayo de 2001 que permite modularizar el HTML para necesidades específicas, las más sobresalientes han sido XHTML-Basic que incluye el conjunto mínimo de características que cualquier navegador debe soportar, incluso de dispositivos móviles y XHTML-MP (mobile profile) con controles aptos para dispositivos móviles.

Entre agosto de 2002 y julio de 2006, el W3C trabajó en XHTML 2.0 que sólo alcanzó el nivel de notas y no de recomendación. En el 2008 el W3C consideraría como base del futuro (X)HTML 5.0, un borrador llamado (X)HTML5 desarrollado por un grupo de interesados, compuesto principalmente por fabricantes de navegadores alternativos (Mozilla Foundation, Opera Software y Apple), ajenos al W3C, que se autodenominaron WHATWG (Web Hypertext Application Technology Working Group). A diferencia de XHTML 2.0, (X)HTML5 estaría más centrado en el desarrollo de aplicaciones web y no en la especificación de documentos. [Nota: En este documento se usarán los términos HTML y XHTML para referirse a cada notación por separado, o (X)HTML cuando algo aplique a ambas por igual].

La segunda guerra de navegadores

Los navegadores en guerra tuvieron equipos de desarrollo enfocados en agregar funcionalidad no estandarizada tan rápido como fuese posible, con poco control de calidad. Esto llevó a que ambos navegadores, Netscape Navigator e Internet Explorer no se apegaran a los estándares, fuesen "pulgosos" e inseguros. Pese de hacerlo público, el código fuente de Netscape fue descartado por la Fundación Mozilla. Por su parte, Microsoft tras ganar la guerra, mantuvo su navegador en el letargo por varios años.

Un navegador no mencionado es Opera. Inició en 1994 como un proyecto de investigación de la compañía noruega Telenor y disponible al público desde 1996 en forma comercial o gratuito con publicidad; hasta la versión 8.5 en setiembre de 2005, en que se distribuye sin costo ni publicidad alguna. Se caracterizó por ser el primer navegador en apegarse a los estándares, influir activamente en ellos, y en la inclusión de características amigables para el usuario, por ejemplo, el uso de "tabs", "mouse gestures", velocidad, seguridad y correr en dispositivos móviles.

La Fundación Mozilla siguió estas características en su navegador gratuito Firefox. Con el objetivo de crear nuevos estándares web que serían sometidos al W3C para aprobación, la Fundación Mozilla y Opera Software fundaron en el 2004 el grupo de trabajo WHATWG (Web Hypertext Application Technology Working Group), al cual se uniría Apple posteriormente.

Las primeras versiones del navegador de Mozilla aparecieron a finales del 2002, con nombres que después serían cambiados por conflictos con otras compañías, hasta quedar Firefox, el cual se liberó en noviembre de 2004. Desde el 2003 Mozilla Firefox empezó lentamente a atraer usuarios de Internet Explorer, en especial por sus problemas y la falta de iniciativa de Microsoft por corregirlos.

Microsoft reaccionó hasta octubre de 2006 con Internet Explorer 7, imitando características de Opera y Firefox. Esto no logró detener la creciente tasa de usuarios que seguían cambiando a Firefox. Por su parte, una semana después, Mozilla liberó Firefox 2.0 con mejoras de usabilidad y seguridad, lo que pondría en evidencia la segunda guerra de navegadores. Esta vez luchando por proveer mayor facilidad de uso y apego a los estándares.

En el 2003 Microsoft anunció que descontinuaría Internet Explorer for Mac. Apple inició el trabajo de crear un navegador que lo reemplazara, ya que era su navegador por defecto, y a partir del motor KHtml usado en Konkeror de KDE generó WebKit y el navegador Safari que apareció en el mismo año.

En el 2008 Google libera el navegador Chrome basado en WebKit. La presencia de estos nuevos navegadores siguen reduciendo el número de usuarios de Internet Explorer [De acuerdo a la estadísticas del W3C en http://www.w3schools.com/browsers/browsers_stats.asp]. Microsoft reacciona con la versión 8 en marzo de 2009 imitando funcionalidades e incrementando el apego a los estándares. Esta guerra se mantiene hasta el presente, donde cada fabricante libera versiones con frecuencia siguiendo la misma estrategia.

Aunque no es un estándar aún, la segunda guerra ha llevado a la mayoría de navegadores a implementar (X)HTML 5.0 o al menos las secciones más estables de sus borradores.

5 pts

Si usted implementara un navegador web que se apegue fiel y únicamente a los estándares ¿Sería útil para que sus usuarios naveguen libremente en la web? Explique en un documento de texto.

Arquitectura web

Un sitio web es un mecanismo de comunicación digital entre autores y visitantes basado en la arquitectura web: un modelo cliente-servidor cuya forma más simple se aprecia en la fig_arqweb y se explica a continuación en forma muy general.

Arquitectura web simple
Arquitectura web simple

El autor que quiera publicar un sitio web, construye un conjunto de páginas web en notación (X)HTML junto con imágenes, estilos y otros medios, y las almacena en una computadora que está siempre conectada a Internet, a la cual se le llama el servidor. Un programa especial, llamado servidor web, el cual tiene acceso de lectura a dichas páginas, estará siempre en esta computadora escuchando por un puerto TCP (Transmission Control Protocol), normalmente el 80 u 8080.

Un lector que quiera visitar el sitio debe conocer la dirección del servidor, es decir su número IP, ya sea introduciéndolo directamente o a través del servicio de nombres de dominio (DNS, Domain Name Service) y el puerto donde el servidor web está escuchando. El lector carga un programa especial en su computadora llamado navegador web (web browser) e ingresa en él la dirección del servidor y el puerto, empleando una notación estándar conocida como localizador uniforme de recursos (URL). El navegador intentará establecer una conexión TCP con el servidor al puerto indicado o al 80 si se omite. El servidor web aceptará la conexión. A partir de este momento el cliente y el servidor pueden comunicarse libremente, pero para que ambos puedan entenderse se necesita un idioma común: el protocolo de transferencia de hipertexto (HTTP, HyperText Transfer Protocol).

El protocolo HTTP establece que el cliente, también conocido como user agent, siempre hace solicitudes de recursos para mostrarlos al usuario, y el servidor responde a ellas, no el recíproco. Las solicitudes del cliente y las respuestas del servidor están codificadas como se verá luego.

En lo que resta de esta sección se explicarán los conceptos que componen la arquitectura web con más detalle y en la siguiente sección, el proceso típico en que un autor construye su sitio web y lo hace público para que los visitantes interaccionen con él.

El servidor web

Un servidor web es un programa cuya ejecución es persistente, a veces llamado servicio o demonio, en un equipo conectado a Internet, esperando conexiones de clientes usualmente por el puerto 80. Una vez establecida una conexión, el cliente solicita repetitivamente recursos al servidor mediante el protocolo HTTP y éste responde a cada una de ellas. El término servidor web también se usa para hacer referencia al hardware que corre este programa, pero en este documento se usará sólo para referirse al software.

Cualquier persona puede implementar un servidor web escribiendo un programa que espere conexiones en algún puerto TCP y hable por él HTTP. Sin embargo, para la mayoría de situaciones, es apremiante utilizar un servidor web existente. La servidores_web lista los más populares en la actualidad.

Nombre Fabricante Licencia Detalles
Apache HTTP Server Apache Libre (Apache License) Rico en características y extensiones. Corre en la mayoría de sistemas operativos. Sirve un poco menos de la mitad de los sitios web del mundo.
Internet Information Services (IIS) Microsoft Propietario / Comercial Sólo se ejecuta en Windows Server. Sirve un poco menos de un tercio de las páginas web del mundo.
nginx Igor Sysoev Libre (BSD) Nació como una alternativa de Apache caracterizada por el alto rendimiento y bajo consumo de recursos. Corre en la mayoría de sistemas operativos. Sirve aproximadamente 15% de las páginas web del mundo.
Google Web Server (GWS) Google Uso interno Sirve aproximadamente 2% de las páginas web del mundo.
lighttpd lighttpd Libre (BSD) Diseñado para ambientes de muy alto rendimiento donde la velocidad es un factor crítico. Es limitado en cuanto a funcionalidad. Sirve aproximadamente un 1% de las páginas web del mundo.
Servidores web más populares en la actualidad de acuerdo a la Netcraft, marzo 2016.
5 pts

Una empresa con bastantes años en el mercado pero sin presencia en internet, le contrata para crear su sitio web. ¿Qué preguntas haría al personal de la empresa con el fin de decidir cuál servidor web recomendar? Idee un par de escenarios. Los escenarios pueden tener esta estructura: "si las respuestas del personal fueran a y b, entonces el servidor recomendable sería w por esta razón: x".

10 pts.

Escoja e instale un servidor web en su máquina local, y establezca el document root de su servidor web como su repositorio local. Consulte la sección sobre el servidor web en este material, o la documentación de su servidor web, o tutoriales en línea, para ayudarse en la configuración del document root. Escriba en un archivo de texto un párrafo indicando la razón de elección del servidor web.

Verifique que pueda navegar por el repositorio local utilizando un navegador, y por tanto en http://localhost/. Su repositorio local y un servidor web local que le permite experimentar los cambios que haga en el código fuente, constituyen su ambiente de desarrollo local. Este ambiente es sumamente importante, porque permite al desarrollador implementar y probar sin afectar el sitio web en producción (el que atiende los visitantes reales).

Como prueba de su ambiente de desarrollo local haga lo siguiente. Cargue la dirección http://localhost/ en su navegador. Redimensione la ventana del navegador a un tamaño cercano a los 640x480 píxeles. Tome una captura de pantalla del navegador. Edite la imagen para que ocupe un tamaño reducido (unos 64kB o menos). Sugerencia, con Gimp puede cambiar la paleta de una imagen PNG a 256 colores (menú Image | Mode | Indexed). Agregue esta imagen a su repositorio de control de versiones.

El cliente web o navegador web

Un navegador web, cliente web, o agente usuario ("user agent"), es un software que permite obtener, presentar, recorrer e interaccionar con recursos disponibles en la web. De los componentes de la arquitectura web, es el más conocido por los usuarios, ya que interaccionan directamente con él.

Un navegador web es una pieza de software compleja, por lo que usualmente está dividida en al menos dos módulos: el motor y la interfaz. El motor del navegador web ("web browser engine" o "rendering engine"), se encarga de analizar contenido ((X)HTML, imágenes, etc.), aplicarle estilos, modificar lo anterior con programas de JavaScript y presentar los resultados en la pantalla u otro medio. Por su parte, la interfaz del navegador web provee una barra de direcciones, marcadores, botones de navegación y otros controles que usan al motor del navegador web internamente para facilitar al usuario su interacción.

La separación entre el motor y la interfaz tiene una importante ventaja. El motor se distribuye en forma de biblioteca y permite que cualquier otra aplicación pueda usarlo. De esta forma, clientes de correo, aplicaciones de ayuda o cualquier software que usted quiera programar, puede manipular documentos web. La browser_engines muestra los motores de "rendereo" web más populares en la actualidad y los navegadores que los usan.

Nombre Fabricante Licencia Navegadores
Gecko Mozilla Project Libre (L/GPL) Firefox
WebKit Apple, KDE, Google, ... Libre (LGPL/BSD) Chrome, Safari
Trident Microsoft Propietario Internet Explorer
Presto Opera Software Propietario Opera
Motores de navegador web más populares en la actualidad.
5 pts

Provea tres ejemplos de aplicaciones de escritorio o de móvil que podrían beneficiarse de utilizar un web rendering engine. Indique rápidamente para qué lo utilizarían.

El localizador uniforme de recursos URL

Un servidor web provee recursos en los que puede estar interesado un cliente. Todo recurso transferible entre el servidor y el cliente, debe estar identificado de forma única en el mundo mediante un localizador uniforme de recurso (URL, Uniform Resource Locator), que es una dirección junto con alguna información adicional para acceder al recurso. La sintaxis de un URL es

esquema://username:password@servidor:puerto/ruta?query_string#id_fragmento
5 pts.

Identifique y señale en los siguientes ejemplos hipotéticos, cada una de las partes del URL:

http://www.amazon.com/
http://www.w3.org/TR/html401/struct/tables.html#edef-CAPTION
http://acme.co.cr:8080/index.php
https://24.168.39.221/cgi-bin/book?id=4596098&action=remove
ftp://msoto:w33n8rf1@down.antivirus.net/current/setup.exe

Escriba en un documento de texto sus resultados. Para cada URL, separe sus partes usando la siguiente estructura:

URL       :
Esquema   :
Servidor  :
Puerto    :
Ruta      :
Parámetros:
Fragmento :
Usuario   :

Las partes de un URL son las siguientes:

  1. Esquema. También llamado Protocolo. Indica el propósito y la sintaxis del resto del URL. Entre muchos se pueden citar: http, https, ftp y mailto. Por ejemplo, al procesar el URL http://www.amazon.com/, un navegador hará un petición HTTP al servidor www.amazon.com en el puerto 80. Al procesar el URL mailto:chema@suizacentroamericana.cr, lanzará un cliente de correo con un mensaje nuevo dirigido a chema@suizacentroamericana.cr.
  2. Servidor. Es la dirección IP o el nombre de dominio si tiene registrado uno en el servicio de nombres de dominio (DNS, Domain Name Service). Permite identificar al servidor que provee el recurso, por ejemplo drupal.org. Dado a que DNS no es sensitivo a mayúsculas ni minúsculas, da lo mismo acceder a DRUPAL.org, por ejemplo.
  3. Puerto. Indica el puerto que será usado en la conexión TCP. Por ejemplo, http://myserver.com:10000/ hará que el navegador establezca una conexión HTTP en el puerto 10000, probablemente para administración del servidor. Si se omite el puerto en el URL se asumirá el por defecto para el esquema usado. Por ejemplo, para http es 80, para https es 443 y para ftp es 21. Una lista de protocolos y sus puertos por defectos puede a conveniencia consultarse en la Wikipedia.
  4. Ruta. Contiene la ruta para encontrar el recurso dentro del servidor. Puede ser relativa al sistema de archivos del servidor o un "alias" que ayude a especificar el recurso, por ejemplo, http://mibibl.net/revistas/acm.png. Es muy probable que sea sensitiva a mayúsculas si el sistema de archivos del servidor lo es también.
  5. Parámetros. Si el recurso es generado por una aplicación en el servidor web, a esta se le pueden enviar parámetros en forma de parejas parametro=valor y separadas por ampersands (&) si son varias parejas, por ejemplo, https://mibibl.net/revista.php?id=23091&action=devolucion&user=chema. A esta lista de parámetros se le suele llamar "query string".
  6. Identificador de fragmento. Es un nombre que sirve para identificar una parte (fragmento) o un punto particular de un documento web. Cuando se especifica un identificador de fragmento en un URL, provoca que el navegador cargue el documento y automáticamente se desplace ("scroll") hasta el fragmento en cuestión. Por ejemplo, http://misitio.co.cr/docs/tesis.html#Cap03.
  7. Usuario y contraseña. Si para acceder al recurso se necesita que el visitante se autentique, algunos protocolos permiten indicar las credenciales en el URL mismo. Es poco común y una práctica no recomendada incluir contraseñas, ya que el URL normalmente es público y carece de seguridad. Ejemplo, ftp://mmortadela@sjmuni.go.cr/vaca/mu.pdf.
5 pts.

Varios caracteres, como el slash (/), el signo de pregunta (?) y el espacio en blanco, tienen un significado especial en un URL. Si un usuario necesita incluir estos caracteres en un URL pero sin su significado especial, investigue y explique cómo se puede hacer. Convierta el siguiente URL en uno válido:

http://localhost/f.php?code="f(n) {return n ? n/f(n-1) : 1;}"

El protocolo de transferencia de hipertexto HTTP

La arquitectura web establece que un servidor web provee al mundo recursos identificados de forma única con URLs. Un cliente web o navegador web interesado solicita estos recursos y el servidor responde con ellos. Las convenciones usadas en el trasiego de estos recursos entre el cliente y servidor las estalece el protocolo de transferencia de hipertexto (HTTP, Hypertext Transfer Protocol).

Cuando el cliente web necesita un recurso, emite un mensaje de solicitud HTTP (HTTP request) al servidor. El servidor web carga el recurso desde el disco, una base de datos, un programa o cualquier otra fuente, y responde con una respuesta HTTP (HTTP response).

Una sesión HTTP (HTTP session), es una secuencia de solicitudes-respuestas entre el navegador y el servidor web. En la versión HTTP/1.0 de 1996 se establece una sesión por cada transferencia. Es decir, se inicia la sesión, el cliente solicita un recurso, el servidor responde y se cierra la sesión inmediatamente. Para transferir un nuevo recurso se debe iniciar otra sesión HTTP. En la versión HTTP/1.1 de 1999 la sesión permite un número arbitrario de transferencias lo que agiliza la comunicación entre ambas partes.

El mensaje HTTP

En la http_message_format se puede ver que la estructura de los mensajes de solicitud y respuesta HTTP es la misma, pero varía el contenido de los primeros dos campos.

Estructura de un mensaje HTTP
Estructura de un mensaje HTTP

La http_message_examples muestra dos ejemplos de mensajes HTTP. Los cambios de línea son importantes por lo que se muestran en rojo. En las siguientes secciones se explica cada uno de los campos que conforman los mensajes HTTP.

Ejemplo de dos mensajes HTTP
Ejemplo de dos mensajes HTTP

Los navegadores sólo muestran el contenido del cuerpo de los mensajes al usuario, ocultando los tres primeros campos de los mensajes usados en la negociación con el servidor web. La extensión HTTP Headers para el navegador Chrome, y Live HTTP Headers para Firefox, permiten al usuario visualizar y estudiar los campos ocultos de los mensajes que se intercambiaron entre el cliente y el servidor durante la carga de una página.

10 pts.

Dibuje en una hoja carta los ejemplos de mensajes HTTP de la http_message_examples. Las siguientes subsecciones explican cada una de sus partes. Haga anotaciones rápidas sobre el dibujo de cada una de las partes. Haga las anotaciones pensando en que le ayudarán en el futuro, como referencia, a comprender de qué se trata cada una de las partes. Finalmente, escanee o tome una fotografía de su dibujo, y agréguela al repositorio de control de versiones. La imagen no debería superar los 200kB.

Request line

En la primera línea del mensaje de solicitud HTTP, llamada Request line, el cliente web indica al servidor el recurso de interés (un URL) y la acción que desea el servidor tome con dicho recurso. La sintaxis del Request line es:

METHOD URL HTTP_version

El protocolo HTTP define 9 acciones que un cliente web puede solicitar al servidor, reciben el nombre de Request methods y se listan en la http_request_methods. El protocolo HTTP indica que todo servidor web debe al menos implementar GET y HEAD, e idealmente OPTIONS.

Método Descripción
GET Solicita una copia completa del recurso cuya identificación esta dada por el URL que le sigue. A través de directivas en el encabezado (el campo que sigue en el mensaje) se pueden hacer solicitudes condicionales (Conditional GET), por ejemplo, obtener una copia del recurso sólo si ha cambiado a partir de una fecha, o una solicitud parcial (Partial GET), por ejemplo, obtener sólo un segmento del recurso. Estos detalles se explican en el RFC-2616.
HEAD Es idéntico al método GET excepto en que el servidor web no debe retornar un Message body en el mensaje de respuesta HTTP. Esto permite al cliente obtener metadatos de un recurso, como para saber si ha cambiado en el servidor u otros fines.
OPTIONS Retorna los métodos HTTP que el servidor soporta para un recurso dado (con un URL) o en general por el servidor web mismo (con un '*' en lugar de un URL).
POST Envía datos, normalmente ingresados en un formulario web, en el campo Message body del mensaje de solicitud HTTP, al recurso identificado por el URL, normalmente un programa en el servidor que procesará o almacenará dichos datos.
PUT "Sube" (upload) un recurso identificiado por el URL cuyo contenido es enviado en el Message body al servidor, el cual reemplaza el recurso anterior si existe. Se diferencia de POST en la semántica del URL. En POST el URL especifica una aplicación que recibe los datos y los procesa; mientras que en PUT el URL es la identificación del recurso mismo.
PATCH Sirve para aplicarle modificaciones parciales a un recurso.
DELETE Solicita al servidor eliminar el recurso identificado por el URL. Normalmente está deshabilitado por defecto en la mayoría de servidores web.
TRACE Permite rastrear servidores intermedios que procesan la solicitud HTTP. Esto es útil para estudiar el comportamiento de servidores proxy en especial si implementan algún caché.
CONNECT Transforma la solicitud en una conexión a un túnel TCP/IP para facilitar la comunicación segura (HTTPS) a través de un proxy HTTP no encriptado.
HTTP Request Methods.

Request header

El campo de encabezado de la solicitud HTTP (HTTP Request Header) permite al cliente proveer información adicional sobre la petición o sobre el cliente mismo al servidor. En este campo se escriben parejas Atributo=Valor. El estándar HTTP define unos 19 atributos de los cuales sólo uno es obligatorio: Host. Los atributos se pueden extender mientras los agentes (el servidor y el navegador) estén de acuerdo en ellos. La request_header_fields muestra algunos de estos atributos.

Campo Descripción
Accept: Permite al cliente especificar los tipos de medios (MIME types) que son aceptables como respuesta. Ej.: Accept: text/plain; text/html; application/html+xml. Un asterisco indica que todas las categorías o todos los medios son aceptables (*/* se asume si no se especifica un atributo Accept). Un párámetro q=valor indica la calidad aceptable, donde valor es un real entre 0.0 y 1.0; útil especialmente en vídeo o ciertos formatos. Si el servidor no puede responder con un formato aceptable, debe generar un mensaje con el status code 406 NOT ACCEPTABLE.
Host: Permite especificar el servidor y el puerto que tiene el recurso solicitado, ya que la primera línea (Request line) no incluye estos valores y se necesitan para desambiguar en caso de servidores proxy u otros intermediarios. Es el único atributo obligatorio en HTTP/1.1. Ej.: Host: www.miservidor.com:8080.
Referer: Permite especificar el URL del recurso del cual se obtuvo el URL solicitado al servidor. Debería ser Referrer:, pero en el estándar aparece como Referer:.
User Agent: Contiene información sobre el navegador o agente de usuario que solicita el recurso. Consta de varias parejas módulo/valor separadas por espacios y en orden de importancia. Todos los agentes de usuario deben proveer este atributo. Ej.: User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:5.0.1) Gecko/20100101 Firefox/5.0.1.
Campos estándar en el HTTP Request header.

Emtpy line

Es un cambio de línea compuesto nada más de dos caracteres: retorno de carro y avance de línea (CRLF, carriage-return y line-feed). En notación C se escribe como "\r\n". Aunque algunos servidores web aceptan un LF simple ("\n"). Esta línea no debe tener ningún otro espacio en blanco.

Message body

Este es el único campo opcional del mensaje HTTP y su contenido varía dependiendo de la naturaleza del mensaje. También es el único que puede transportar información binaria (todos los demás son de texto).

Status line

En la línea Status line del mensaje de respuesta HTTP, el servidor indica al cliente web, un código y una explicación textual como resultado de procesar la solicitud previamente hecha. La sintaxis del Status line es:

HTTP_version status_code reason_phrase

El status_code es un número y el reason_phrase es un texto corto escogido por el servidor web y comprensible para seres humanos; el navegador no necesita analizarlo. El status_code es entero de tres dígitos, donde el primer dígito indica una de las cinco clases de respuesta definidas por el estándar HTTP:

  1. Información. La solicitud fue recibida y está siendo procesada.
  2. Éxito. La solicitud fue recibida, entendida, aceptada y procesada exitosamente.
  3. Redirección. Se necesitan más acciones del cliente para completar la solicitud.
  4. Error del cliente. La solicitud es incorrecta por error de sintaxis o no se puede realizar.
  5. Error del servidor. El servidor falló al procesar una solicitud aparentemente válida.

Por ejemplo, el error 404 NOT FOUND indica que el cliente especificó un URL de un recurso que no existe en el servidor. El RFC 2616 de HTTP/1.1 define 41 status_codes, algunos de los más comunes son los siguientes:

  • 200 OK. La solicitud HTTP fue exitosa. Por ejemplo, si la solicitud fue un GET, la respuesta contendrá el recurso solicitado en el campo Message body; si la solicitud fue un POST, los datos enviados por el cliente fueron procesados exitosamente.
  • 204 NOT CONTENT. El servidor procesó la solicitud exitosamente, pero no es necesario generar un recurso como respuesta y por ende el campo Message body está vacío.
  • 206 PARTIAL CONTENT. El servidor responde con un fragmento del recurso solicitado, tal como fue pedido por el cliente web. Esto es de utilidad para continuar descargando un recurso incompleto o permitir varias descargas simultáneas en partes diferentes del mismo recurso. Esta funcionalidad es ampliamente explotada por los administradores de descargas (download managers).
  • 301 MOVED PERMANENTLY. El recurso ha sido movido a otro URL y el cliente debe obtener el nuevo recurso con una nueva solicitud.
  • 302 FOUND. No debería usarse. Normalmente se quiere decir 303.
  • 303 SEE OTHER. El recurso está disponible en otro URL, el cual el cliente debe obtener con una solicitud nueva. Puede usarse para evitar sobrecargar un servidor web o redireccionar algún recurso.
  • 400 BAD REQUEST. La sintaxis de la solicitud es incorrecta.
  • 401 UNAUTHORIZED. El cliente intenta acceder a un recurso que está protegido y no ha provisto credenciales o las ha fallado. La respuesta incluye un reto al usuario, el cual debe proveer un nombre de usuario y contraseña.
  • 403 FORBIDDEN. La solicitud es válida pero el servidor se niega a completarla, por ejemplo, tras varios intentos el usuario falla el proceso de autenticación.
  • 404 NOT FOUND. El recurso no se encuentra pero podría estarlo en el futuro.
  • 410 GONE. El recurso no se encuentra y nunca más lo hará. Es útil para avisar a los motores de búsqueda que eliminen el recurso de sus índices.
  • 500 INTERNAL SERVER ERROR. Mensaje genérico, para cuando no hay uno 5XX más específico.
  • 501 NOT IMPLEMENTED. El request method o alguna característica es válida ante el estándar, pero el servidor web no lo implementa.
  • 503 SERVICE UNAVAILABLE. El servidor web no está disponible por sobrecarga o en mantenimiento. Normalmente una condición temporal.

Para revisar la lista completa de códigos de estado HTTP con los que puede responder un servidor, consúltese el RFC 2616.

Response header

El campo encabezado de respuesta HTTP (HTTP Response Header) permite al servidor enviar información adicional sobre la respuesta al agente de usuario. Utilizan la misma notación que los del campo encabezado de solicitud HTTP y también se pueden extender mientras los agentes estén de acuerdo en ellos. Algunos se explican en la siguiente tabla.

Campo Descripción
ETag: Contracción de "Entity Tag". Es una cadena que permite identificar el estado del recurso, de tal forma que si se hace una modificación del recurso en el servidor, su ETag variará. Esto permite al cliente saber si su copia en el caché está actualizada o ha variado en el servidor. Ej.: Etag: "239876f-4b8c-429fe67474a80".
Location: Permite al servidor indicarle al agente de usuario que el recurso solicitado ha sido movido a un nuevo URL. El agente usuario debe entonces solicitar el nuevo recurso, lo que se conoce como una "redirección".
Server: Contiene información sobre el servidor web que genera la respuesta. Consta de varias parejas módulo/valor en orden de importancia para identificar al servidor. Ej.: Server: Apache/2.2.9 (Debian) PHP/5.2.17-0.dotdeb.0.
WWW-Authenticate: Solicita al usuario autenticarse para acceder a un recurso en una respuesta 401 UNAUTHORIZED. Es seguido por el número de intentos permitidos. Ej.: WWW-Authenticate: 3.
Campos estándar en el HTTP Response header.

Ejemplo de una sesión HTTP

Supóngase que el sitio web ubicado en www.ejemplo.com está en construcción y tiene sólo dos recursos, un index.html y una imagen img/ucr.png. El contenido del recurso index.html se encuentra en el some_index_page.


   Desarrollo de aplicaciones web
   
      Escudo UCR
      Escudo ECCI
      

Presentación

En este curso el estudiante aprenderá a[...]

]]>
Contenido de una página web hipotética

Un visitante accede con su navegador a www.ejemplo.com. La interacción entre el navegador web y el servidor web se aprecia en el diagrama de secuencia de la http_session_example_img.

Diagrama de secuencia de una sesión HTTP
Diagrama de secuencia de una sesión HTTP

Al escribir la dirección http://www.ejemplo.com/ el navegador contacta al "default gateway" que tenga configurado el sistema operativo de la máquina local y le pide que le resuelva la dirección IP del dominio www.ejemplo.com. Al obtener la dirección IP, el navegador establece una conexión TCP en el puerto 80 con www.ejemplo.com y éste acepta. A partir de este momento se ha establecido una sesión HTTP; el navegador y el servidor web pueden intercambiar mensajes HTTP.

El navegador solicita el recurso que el usuario indicó en el URL, en este caso es "/". Ensambla un mensaje HTTP Request con el método GET, escribe algunos campos de encabezado (HTTP Request Header fields) y un cambio de línea. Lo envía al servidor.

El servidor recibe la solicitud HTTP y de acuerdo a su configuración local, obtiene que el recurso "/" equivale al archivo index.html. Ensambla una respuesta HTTP (HTTP Response message) con el status code 200 indicando que el recurso fue encontrado y la solicitud se procesó exitosamente. Agrega unos campos de encabezado de respuesta (HTTP Response Header fields) y anexa el contenido del recurso index.html literalmente en el campo Message body. Lo envía al cliente.

El navegador recibe el mensaje de respuesta HTTP y viendo que la solicitud fue exitosa, extrae el recurso index.html guiado por los campos de encabezado HTTP. Almacena el recurso en su caché. El web rendering engine del navegador inicia el análisis (parsing) y despliegue (rendering) del recurso en la ventana del usuario. Al analizar la línea 4 del index.html, el navegador se percata de que necesita otro recurso para presentarlo en la página, y ensambla otra solicitud al servidor, de la misma forma que hizo con index.html, pero esta vez por img/ucr.png.

El servidor web recibe la nueva solicitud y la procesa de la misma forma que hizo previamente con index.html. El recurso también existe. La única diferencia es que img/ucr.png es un recurso binario, de ahí la importancia de los campos del encabezado que ayudarán al navegador a procesar el recurso adecuadamente, en especial el Content-type: image/png. El servidor envía el mensaje de respuesta.

El navegador recibe el mensaje y al ver que es exitoso, agrega el recurso en su caché y guiado por los campos del encabezado del mensaje, interpreta el contenido binario como una imagen PNG y el motor de rendering la coloca en su lugar dentro de la ventana. Al analizar la línea 5 del documento index.html (some_index_page), se percata de que necesita también el recurso img/ecci.png. Ensambla una nueva solicitud GET y la envía al servidor como hizo anteriormente.

El servidor web recibe la solicitud y trata de localizar el recurso. Al notar que no se encuentra en su sistema de archivos, construye una respuesta HTTP con status code 404 Not Found, indicando que el agente del usuario solicitó un recurso erróneo. En el cuerpo del mensaje agrega un texto más explicativo y en los campos del encabezado HTTP detalles de cómo interpretar este texto. Lo envía al cliente.

El navegador recibe el mensaje 404 Not Found. Al no obtener un recurso para desplegar (render), opta por dibujar un rectángulo genérico indicando la ausencia y rellena con el texto alternativo que se encuentra en el documento index.html. Continúa de esta forma analizando y desplegando el recurso index.html hasta alcanzar su final.

5 pts.

¿Se puede tener dos servidores web instalados y activos en un mismo equipo? Si la respuesta es afirmativa ¿cómo harían para diferenciar cuáles peticiones de los clientes le pertenece a cada uno?

5 pts.

¿Cuáles son los pasos que realiza un servidor web para encontrar en el sistema de archivos local un recurso solicitado a través de un URL? Por ejemplo, si intenta acceder a:

http://localhost/bio/foto.jpg

¿a qué archivo de su sistema de archivos, exista o no, intenta acceder el servidor web? ¿A qué recurso intenta acceder el servidor web cuando se le solicita simplemente la siguiente dirección?

http://localhost/
15 pts.

Indague cómo tener una sesión con un servidor web a través de telnet. Escoja un sitio que visite con frecuencia y hable HTTP con el servidor. Actúe como un navegador. Solicite al menos una página HTML, un recurso binario que sabe que existe en el servidor, y un recurso que no existe. Transcriba su sesión telnet a un documento de texto.

5 pts.

Un usuario tiene cargada una página web y presiona el botón de refrescar. ¿Cómo debería el navegador web implementar esta operación? ¿Existe algún mecanismo eficiente para reducir el tráfico de red?

Proceso de construcción del sitio web

Al igual que cualquier otro software, la construcción de un sitio web sigue un proceso de desarrollo, con las fases conocidas: análisis para saber qué necesita el cliente; diseño del sitio; implementación de los documentos y aplicaciones web; pruebas (testing) del sitio y las aplicaciones web; y el mantenimiento del sitio.

Se debe tener muy claro que el equipo de desarrollo de un sitio web, o simplemente el equipo web, es una entidad multidisciplinaria y no sólo uno o más informáticos. Este equipo puede estar conformado por varios tipos de profesionales, entre los que son frecuentes:

Diseño del sitio web

La fase de análisis pretende conocer el problema, es decir, obtener el propósito del sitio web, las necesidades que resuelve, los visitantes que lo usarán, entre otros detalles. La fase de diseño pretende elaborar un modelo de sitio web que solucione las necesidades halladas en la fase de análisis. En esta etapa se decide:

  1. Qué tecnologías usar, por ejemplo: páginas estáticas, un administrador de contenido (CMS), programación PHP, bases de datos orientadas a documentos.
  2. La arquitectura de los componentes que intervendrán.
  3. La apariencia del sitio: estilos, si se usará una metáfora o no.
  4. Las convenciones: nombres de los archivos, reglas de escritura del código fuente, ...

Sin un buen diseño el programador se sentará frente a la computadora sin saber cómo empezar el sitio web, ni qué secciones tendrá, ni cuáles de ellas tendrán páginas estáticas o serán programadas, etc. La importancia de la fase de diseño web es tal que libros completos atienden el tema, como "Web Style Guide" de Patrick J. Lynch y Sarah Horton, cuyo texto completo se encuentra disponible en línea gratuitamente.

20 pts.

En este curso usted debe crear un sitio web para alojar los ejercicios de este material. Haga un diseño preliminar de su sitio web personal. Este diseño debe tener al menos:

  1. El propósito de su sitio y quién es el autor.
  2. La apariencia del sitio. Dibuje en SVG o en papel a escanear, las zonas que definen el sitio y cómo quiere que se vean. Ejemplo: encabezado, pie de página, menú principal, contenido.
  3. La jerarquía de contenido: Las secciones y subsecciones de contenido. A modo de sugerencia puede seguir la misma estructura de este material (intro, xml, html, css, js y php). Refleje esta estructura en el menú del dibujo en el punto anterior.
  4. Las convenciones que utilizará para nombrar las carpetas y los archivos. En especial: documentos de contenido, las imágenes, hojas de estilo y scripts.
  5. Las convenciones de identificadores para los diferentes lenguajes que tendrá su sitio: HTML, CSS, JS y PHP. Ejemplos de convenciones son camelCase, under_scores, o con-guiones.

Documente su diseño en un archivo README.txt en la raíz de su repositorio de control de versiones, y no en una carpeta student_site_design. Pero sí use el identificador student_site_design para los commits relacionados en su repositorio de control de versiones. Las imágenes que genere en este ejercicio, ubíquelas y nómbrelas de acuerdo a la convención que haya tomado para ellas.

Alojamiento web

Para publicar su sitio web el autor debe, adquirir una o más computadoras; configurarlas como servidores web, bases de datos u otros servicios; contratar suficiente ancho de banda; velar porque el servicio no se interrumpa pese a fallos eléctricos con UPS (Uninterruptible Power Supply) y generadores eléctricos, o fallos en el proveedor de servicios de Internet (ISP, Internet Service Provider) con redundancia de conexiones; fallos de hardware (como malfuncionamiento de un disco duro) y otra serie de consideraciones para que el sitio esté disponible al menos el 99% del tiempo.

Muchos autores prefieren relegar estas responsabilidades a una compañía que se especialice en brindar este tipo de servicio, el cual recibe el nombre de alojamiento web (web hosting). La oferta de proveedores de alojamiento web es considerable, y varía en precios desde lo gratuito hasta lo costoso.

Las compañías de alojamiento web proveen varios tipos de alojamiento. Un listado de tipos de alojamiento web puede verse en http://en.wikipedia.org/wiki/Web_hosting_service, de los cuales sobresalen los siguientes.

  1. Servidor compartido (shared hosting). Es la variante más común y la más económica. Su sitio web comparte el mismo servidor web con otros sitios que estén alojados en el mismo servidor físico. Usted no tiene derechos de administración, ya que un cambio en la configuración del servidor web afectaría a los otros sitios.
  2. Servidor dedicado virtual o servidor privado virtual (VPS, Virtual Private Host). Usted alquila una máquina virtual, la cual es de su uso exclusivo (privado) y por ende tiene permisos de administración sobre ella. Puede, por ejemplo, reiniciarla o instalar paquetes. Dado que varias máquinas virtuales comparten el mismo servidor físico, su sitio competirá por los recursos de hardware con las otras máquinas virtuales en la misma máquina.
  3. Servidor dedicado (dedicated hosting). Un servidor físico que es para su uso exclusivo, no compartido con nadie.
  4. Alojamiento en la nube (cloud hosting). Su sitio web no estará en un único servidor, sino distribuido en varios de ellos. Esto tiene grandes ventajas, como la posibilidad de responder a una inmensa cantidad de visitantes simultáneamente, la facilidad de expansión y la capacidad de continuar activo pese a que un servidor físico esté caído. Sin embargo, desarrollar y mantener un sitio web distribuido tiene mayor nivel complejidad que uno centralizado.

Para sitios pequeños o muy incipientes, el autor puede beneficiarse de servicios de alojamiento web gratuitos. El sitio Free Web Hosting lista y compara varios servicios de alojamiento gratuitos. Antes de decidirse por uno, el autor debería revisar los términos de servicio y otros detalles para evitar sorpresas.

10 pts.

Usted tiene un repositorio de control de versiones y uno de sus clones es un ambiente de desarrollo local. Publique su repositorio en un sitio web en producción para curso. Solicite al profesor una cuenta en el servidor web de la ECCI para el curso (http://cursoweb.ecci.ucr.ac.cr/). Ingrese por SSH y clone su repositorio en una carpeta public_html para su sitio web dentro de su directorio personal, algo como:

$ ssh user@cursoweb.ecci.ucr.ac.cr
Password: (cursoweb password)

$ git clone https://url/to/my/repo.git public_html
Password: (git server password)

Cada vez que haya hecho cambios en su repositorio y quiera reflejarlos en su sitio web en producción, puede ingresar por SSH al servidor y emitir un comando git pull dentro de la carpeta public_html:

$ ssh user@cursoweb.ecci.ucr.ac.cr
Password: (cursoweb password)

$ cd public_html
$ git pull
Password: (git server password)

La dirección de su sitio web personal en producción tendrá la forma http://cursoweb.ecci.ucr.ac.cr/~user/, reemplazando user por su nombre de usuario.

Registro de dominio

La mayoría de sitios web se conocen por un nombre de dominio como www.ejemplo.com. Cualquier persona puede registrar un nombre de dominio, pero siempre tiene un costo económico. En la actualidad es cercano a los 10 dólares anuales. Los precios varían dependiendo principalmente de dos características:

  1. El dominio de nivel superior (TLD, Top-Level Domain) que se quiere tener. Los precios varían dependiendo del tipo de dominio superior. Los dominios de nivel superior más conocidos son los genéricos: .com para el comercio, .org para organizaciones, y .net para entidades relacionadas con Internet. Hay dominios geográficos, administrados por países, por ejemplo .cr para Costa Rica y uk para Reino Unido. Los dominios propuestos permiten definir dominios arbitrarios, como .club o exclusivos como .bmw.
  2. El registrador de dominio (en inglés, domain name registrar). Es la compañía que realiza el registro del dominio y de mantenerlo vigente año con año. El servicio DNPric.es permite comparar tarifas de varias registradores de dominio.

Cuando se registra un nombre de dominio, éste se debe convertir en pertenencia del autor y no del registrador del dominio. El autor puede entonces asociar el dominio con cualquier servidor web, sea propio, de un servicio de alojamiento gratuito, o uno comercial. Incluso, el autor puede cambiar de registrador de dominio, lo que se conoce como transferir el dominio. Cuando se contrata un servicio de alojamiento web comercial, es común que se incluya el costo de registro y renovación del nombre de dominio año con año.

Los nombres de dominio se asocian a direcciones IP. Cuando un cliente escribe una dirección web como www.ejemplo.com, el navegador le pedirá al sistema operativo que trate de conseguir la dirección IP de www.ejemplo.com. El sistema operativo preguntará a un servidor de dominio (DNS) que tendrá en su configuración, que resuelva el URL www.ejemplo.com. En el proceso es normal que se tenga que contactar varios servidores de dominio hasta encontrar la dirección IP asociada a www.ejemplo.com.

La dirección IP no es el único dato asociado a un nombre de dominio. Se asocia abundante información pública a los nombres de dominio que puede consultarse con un servicio de "whois", por ejemplo http://whois.domaintools.com/.

5 pts.

Averigüe la dirección IP del dominio que aloja su sitio web público en producción, cuándo expira el dominio, el nombre del registrador de dominio, y quiénes son los contactos (las personas físicas) responsables del dominio.

5 pts.

Suponga que usted trabaja como el encargado del sitio web para una empresa, la cual realiza comercio electrónico. Usted descubre accidentalmente que existe un sitio web cuya página principal es una copia idéntica a la del sitio web de la empresa. La página falsa tiene un dominio muy parecido al de la empresa, pero intercambiando dos caracteres que son fáciles de digitar incorrectamente cuando se escribe rápido en el teclado. Probablemente la página falsa se creó con el fin de interceptar las contraseñas de los usuarios de la empresa (en inglés phishing). ¿Qué mecanismos dispone usted como informático para defender su empresa? ¿Cuál usaría?

5 pts.

Suponga que su empresa tiene un dominio web registrado y un sitio web en producción, digamos en http://suempresa.com. Su empresa quiere abrir un portal privado para los empleados, por lo que se usarán contraseñas. Se quiere que haya una versión segura del sitio en https://suempresa.com. ¿Debe su empresa registrar un nuevo dominio para servir su sitio web en https? Explique por qué sí o por qué no.

Construcción del contenido

Una vez que se ha determinado la necesidad de un sitio web, se ha diseñado una solución, se tiene alojamiento gratuito o no, y opcionalmente asociado a un nombre de dominio; el autor estará interesado en escribir el contenido del sitio web.

Quizá el método más rápido y eficiente de construir un sitio web sea a través de páginas estáticas. Es decir, un conjunto de documentos (X)HTML escritos manualmente o con ayuda de algún software de diseño web, además de otros recursos como hojas de estilo, imágenes y programas en JavaScript. Esto puede ser conveniente para sitios web sencillos y pequeños.

Cuando un sitio web se torna extenso con cientos o miles de documentos web, intervenido por muchos usuarios que aportan información, o que debe solventar necesidades especificas que sólo con programación puede atenderse; se debe convertir en un sitio web dinámico. En tal caso el autor debe escoger algún medio de programación en el lado del servidor, como CGI, algún lenguaje de "scripting" como PHP, alguna solución existente como un administrador de contenido (CMS), o un framework para desarrollo de aplicaciones web, entre otras posibilidades.

Promoción del sitio web

Una vez que el sitio web está publicado, el autor estará interesado en que la audiencia interaccione con él. Es difícil que entre millones de sitios web en el mundo un visitante encuentre el de uno. No obstante, algunas estrategias pueden ayudar.

El principal medio en la actualidad para encontrar algo de interés en el web es a través de un buscador, como Google o Bing. Normalmente estos buscadores proveen algún mecanismo para solicitarles que consideren incluir un dominio en sus índices.

Aunque el sitio web sea incluido en los índices de los buscadores, es muy probable que no aparezca entre los primeros resultados de una consulta. Esto se puede mejorar incrementando la "popularidad" del sitio. Los buscadores miden qué tan popular es un recurso en proporción a la cantidad de enlaces que encuentran hacia dicho recurso en otros dominios. Por eso, enlazar el sitio web en diarios, noticias, listas de correo u otros medios puede ayudar.

Una alternativa más es invertir en publicidad local o internacional. Incluso se puede costear un lugar privilegiado en los resultados de los buscadores más populares.

5 pts. Aparte de su sitio web personal, describa un caso o una necesidad web que quiera satisfacer. Puede ser un sitio o una aplicación web para un familiar, una organización, o interés propio. Describa, de forma muy general, la necesidad y la tecnología que utilizaría para satisfacerla.

El lenguaje de marcado extensible XML

Los seres humanos tienen diversas necesidades de información, y cuando ésta se debe almacenar en la computadora, se suele hacer en forma de bases de datos o documentos digitales. Las bases de datos restringen en alguna medida la representación de información del mundo real a una estructura que debe definirse formalmente para poder ser eficientemente manipulada por el computador. Elaborar una base de datos es una tarea compleja que consume recursos considerables. Los documentos por el contrario, son menos estrictos por lo que pueden representar casi cualquier tipo de información del mundo real, pero tal libertad limita el poder de manipulación del computador. El XML es un lenguaje formal que busca las ventajas de ambos: la representación flexible de información en forma de documentos que pueden ser manipulados aprovechando el poder del computador.

El lenguaje de marcado extensible (XML, eXtensible Markup Language), es un conjunto de reglas estándar para representar información en forma de documentos digitales, que se caracteriza por permitir marcado definido a conveniencia del autor. Representar digitalmente un documento implica transformarlo en algún tipo de código legible por la computadora para que ésta sea capaz de almacenarlo, procesarlo, buscarlo, transmitirlo, mostrarlo e imprimirlo [Gold99].

A modo de ejemplo, supóngase que un profesor quiere anotar en su computadora varias ideas sobre el curso que va a impartir. No crea una base de datos para ello, sino que crea un nuevo documento y escribe algún texto como el que se aprecia en el ej_plain_doc



Este documento contiene un resumen de temas que servirán de
apoyo a los estudiantes del curso CI-2413 impartido en la Universidad...



INTRODUCCIÓN A LA TECNOLOGÍA WEB

De todas las aplicaciones que se han construido sobre Internet, la
World Wide Web (WWW o simplemente web) ha sido la más popular, tanto que,
muchas personas cuando escuchan el término "Internet" realmente[...]

La popularidad de la web puede adjudicarse a su facilidad de uso y por
ser el más exitoso de los sistemas distribuidos en la actualidad. Los
documentos se almacenan en computadoras distintas, con sistemas[...]


Historia de la web

La web fue conceptualizada en un artículo de 1989 de Tim Berners-Lee,
quien se convertiría en uno de sus grandes líderes. A finales de 1990,
Berners-Lee desarrolló el Protocolo de transferencia de hipertexto[...] ]]>
Ejemplo un documento sin estructura.

En un inicio el documento resulta muy práctico, pero conforme crece en tamaño y complejidad se descubren las imposibilidades de procesamiento del computador. Por ejemplo, no hay forma de decirle al computador que automáticamente enumere los títulos y cree una tabla de contenidos, porque simplemente no se ha identificado cuáles son los títulos en el documento. Sin embargo, el autor podría utilizar alguna convención para distinguir los títulos, por ejemplo, precederlos por varios cambios de línea, en proporción inversa al nivel del título; o emplear caracteres especiales. Cualquiera que sea el caso, el autor debe ser cuidadosamente consistente con su notación. Luego tendría que programar algún software que guiado por estas convenciones, cree el índice en forma automática, y provea otras funcionalidades similares.

Supóngase que otro profesor, con la misma necesidad de representar información de un curso en su computadora, crea una convención distinta, y además un software distinto. Además del trabajo redundante, estos dos autores no podrán compartir sus trabajos ya que desconocen sus notaciones. Aquí es donde tiene cabida XML. XML es simplemente un conjunto de convenciones para escribir documentos y un conjunto de reglas estándar que le dice a los software cómo deben procesar esos documentos guiados por las necesidades de los autores. El documento del ej_plain_doc podría representarse como el xml_eg_book en XML.





   Aplicaciones web
   
      
         Jeisson Hidalgo-Céspedes
         jeissonh@gmail.com
      
   

   
      
Prólogo

Este documento contiene un resumen de temas que servirán de apoyo a los estudiantes del curso CI-2413 impartido...

Agradecimientos

Quiero agradecer en primer lugar, a usted, que con sus ojos da vida a estas inanimadas palabras pintadas en...

Introducción a la tecnología web

De todas las aplicaciones que se han construido sobre Internet...

Su popularidad puede deberse a su "facilidad de uso" y...

Historia

La web fue conceptualizada en un artículo de 1989 Tim Berners-Lee

]]>
Ejemplo de un libro hipotético en XML. Obtener archivo.

Un documento XML es un archivo de texto. El texto se clasifica en tres tipos: datos de carácter, elementos y entidades. Los datos de carácter corresponden al texto normal que el autor quiere escribir, como el presentado originalmente en el ej_plain_doc. La computadora poco puede hacer con este texto, por ejemplo, no puede crear la tabla de contenidos porque no sabe cuáles partes del texto son los títulos. XML solicita al autor que además de escribir el texto, distinga claramente cada parte del mismo. En terminología XML, una parte de un documento se conoce como elemento. Por ejemplo, los elementos que componen un libro son: portada, tabla de contenidos, partes, capítulos, secciones, párrafos, palabras, títulos, notas, etc. Finalmente, las entidades XML permiten darle nombre a un trozo de información (incluso binaria) y reutilizarla en una o varias partes del documento.

Los elementos se pueden anidar, formando un árbol. Los elementos dentro de otros se llaman elementos hijos y a los contenedores, elementos padres. Sólo puede existir un único elemento raíz, también llamado elemento documento, que contiene a todos los demás [Marc00]. En el xml_eg_book el elemento con identificador book es elemento raíz. El elemento es sin duda el constructo XML más frecuente que usará un autor, sin embargo, antes de empezar a escribirlos, el autor debe proporcionar otros detalles sobre el documento XML que se explican a continuación.

5 pts.

Describa un ejemplo de una situación en que usted se hubiera beneficiado de haber representado información en XML. Puede ser un proyecto de programación que hizo en algún curso previo, o un proyecto profesional en que haya participado. Sugerencia: piense en archivos de texto sin estructura o bases de datos que haya utilizado previamente.

5 pts.

En los sistemas operativos basados en Unix, es común que los programas guarden su configuración en archivos de texto. Por ejemplo, la configuración de dispositivos y particiones se configura en /etc/fstab, los programas a ejecutar de forma periódica en /etc/crontab; el intérprete de comandos Bash guarda su configuración en un archivo oculto .bashrc en la carpeta del usuario, el servidor web Apache en varios archivos de texto en la carpeta /etc/apache2, el servidor de SSH en /etc/ssh/; entre muchos otros. Cada uno de estos programas utilizan una notación diferente para representar su configuración. Liste ventajas y desventajas si todos estos programas utilizaran notación XML para representar sus configuraciones.

5 pts.

Muchos programas registran eventos o errores en bitácoras. Por ejemplo, todas las solicitudes HTTP que el servidor web Apache recibe se registran en /var/log/apache2/access.log, y los eventos de arranque o de solicitudes al kernel de Linux se registran en /var/log/messages. Normalmentelas bitácoras son archivos de texto y cada programa utiliza su propio formato. ¿Sugeriría usted que las bitácoras se escriban en XML? Justifique su respuesta.

Encabezado de documento

Los documentos XML constan de dos partes: encabezado (head) y cuerpo (body). El encabezado de un documento XML recibe el nombre de prólogo de documento y almacena información que describe al cuerpo del documento, como la versión de XML, el tipo de documento (DTD) al que pertenece, la codificación y otros. El cuerpo del documento XML recibe el nombre de instancia de documento, que contiene los datos reales del documento.

El prólogo de un documento suele incluir la declaración de XML y la declaración del tipo de documento, en ese orden; además de otras características como comentarios e instrucciones de procesamiento. Todas son opcionales, pero se aconseja maximizar la cantidad de información en el prólogo ya que ayuda al procesamiento posterior del documento [Gold99]. El prólogo termina cuando abre la etiqueta de inicio del elemento raíz, es decir, donde inicia la instancia de documento.

La declaración XML

La declaración XML indica que el documento usa notación XML e indica la codificación del mismo. Tiene la forma mínima <?xml version="1.0"?> y no posee una etiqueta de cierre. Tiene tres atributos: la versión, la codificación y el documento autónomo:

  • La declaración de versión con el atributo version, indica la versión de XML utilizada en el documento. Normalmente "1.0".
  • La declaración de codificación con el atributo encoding, indica la codificación de caracteres del documento. Aunque los procesadores XML tienden a reconocer automáticamente la codificación, es mejor indicarlo explícitamente, por ejemplo, "UTF-8", "UTF-16" o "iso-8859-1" [Gold99]. Lo importante es que este atributo refleje realmente el tipo de codificación que usó para generar el documento.
  • La declaración de documento autónomo con el atributo standalone no se suele utilizar con frecuencia ni tampoco se recomienda su uso. Su comprensión es compleja y se explica ampliamente por Goldfarb [Gold99].

A modo de ejemplo, la declaración XML en su forma más amplia tiene la siguiente forma:

]]>
5 pts.

Suponga que un cliente tiene repetidas dificultades para localizar eficientemente activos en su empresa dispersa en varias sucursales, y le ha contratado para que le desarrolle un sistema de administración del inventario, el cual debe ser accesible vía web. Usted decide utilizar documentos XML para representar los activos y así transferirlos entre el navegador y el servidor web mediante AJAX.

Cree un documento XML vacío, que en ejercicios posteriores utilizará para ir representando el inventario. Utilizando un editor de texto, cree un archivo con extensión .xml. Incluya la declaración XML. Declare la codificación como utf-8 y asegúrese de que su editor de texto esté realmente utilizando esta codificación. Sugerencia: indague las facilidades que disponga su editor de texto para ayudar en la edición de código XML, como autocerrar etiquetas.

Guarde su documento en una carpeta xml_inventory. Para los ejercicios posteriores que utilizan este archivo, no cree uno nuevo, sino que por cada ejercicio realice al menos un commit con los cambios que haya hecho a este archivo.

La declaración del tipo de documento

Es sabido que las cartas, tesis, guiones y las guías telefónicas son documentos que tienen una estructura muy diferente. Es decir, poseen elementos distintos, cada uno con su propia distribución y orden. Se dice que son tipos de documentos distintos. En XML cada tipo de documento se define en una notación formal que plasma su estructura llamada definición de tipo de documento (DTD, Document Type Definition) y se estudiará luego. Un documento puede declarar que es de un tipo de documento particular utilizando la declaración de tipo de documento, como se hizo en la segunda línea del xml_eg_book, indicando que ese documento es de tipo "book":

]]>

Se puede pensar en un DTD como una clase en programación orientada a objetos, mientras que un documento XML que sea de ese tipo de DTD es como un objeto que instancia esa clase. El "objeto" documento XML debe cumplir a cabalidad con la estructura descrita en su DTD, cuando esto ocurre, se dice que el documento es de tipo válido o simplemente válido, de lo contrario, se dice que el documento es de tipo no válido o simplemente no válido (o incluso, inválido) [Gold99].

Un documento XML puede no tener un tipo de documento definido, es decir, carece o no cumple con un DTD, por lo que es un documento no válido pero puede respetar la sintaxis XML, en tal caso se dice que sólo es un documento bien formado (well formed). Los documentos bien formados pero no válidos (no cumplen un DTD) suelen utilizarse para documentos pequeños que deben escribirse de forma rápida. Los documentos válidos siempre están bien formados y son necesarios cuando son muy extensos o deben procesarse por algún sistema computacional [Gold99].

La declaración DOCTYPE indica el tipo de documento y además instruye al procesador de XML dónde encontrar la definición del tipo de documento (DTD), el cual puede estar escrito en el mismo documento XML o puede encontrarse en una entidad externa (un archivo en disco o red) o una combinación de ambas. Lo más común es que se encuentre en un recurso externo, como se hizo en la segunda línea del xml_eg_book, la cual instruye al procesador XML que el tipo de documento está en el archivo "book.dtd" en la misma ubicación que el documento XML. La palabra SYSTEM indica al sistema que busque el recurso especificado en el URI (Universal Resource Identifier) que le continúa. Más adelante se estudiará la nomenclatura de un DTD.

El identificador del elemento que continúa inmediatamente después de <!DOCTYPE, por ejemplo, book en el xml_eg_book, indica al procesador XML a partir de qué elemento del DTD se debe incluir, es decir, sólo se incluye el subárbol cuya raíz es precisamente ese elemento.

En XML los identificadores se usan para dar nombre a los elementos, entidades u otros. Por ejemplo, la línea 3 del xml_eg_book incluye tres identificadores: book, name y version. Los identificadores deben iniciar con una letra y pueden estar seguidos de cero o más letras o los caracteres punto, guión o dígitos. Los identificadores en XML son sensitivos a mayúsculas y minúsculas (case sensitive), esto implica, por ejemplo que book, Book y boOK se tomen como identificadores distintos. El autor puede emplear cualquier identificador válido, excepto aquellos que inician con la cadena "xml" en cualquiera de sus combinaciones de mayúsculas y minúsculas, ya que están reservados para propósitos de estandarización [Gold99].

5 pts.

Declare el tipo de documento en el archivo XML que creó en el ejercicio anterior. El nombre XXX que escoja para su DTD debe completar la frase "Este documento es un XXX", o "Este documento contiene un XXX". Luego cree un archivo de texto vacío en codificación utf-8 con nombre XXX.dtd y en la misma carpeta donde está su archivo .xml creado en el ejercicio anterior.

Elementos y atributos

Elementos

Los elementos son las partes que componen un documento. El autor debe indicar entre todo el texto que compone el documento, qué trozo es cada parte. Sintácticamente un elemento se forma marcando la parte del documento entre dos etiquetas. Es decir, el texto (datos de carácter) que conforma un elemento se encierra entre un par de etiquetas. Una etiqueta es el texto entre un par de signos "menor que" y "mayor que". Sintácticamente, un elemento es la combinación de una etiqueta de inicio (que puede tener atributos), un contenido opcional, y una etiqueta de cierre, de la siguiente forma:


contenido

]]>

Un elemento tiene dos etiquetas, una de inicio y otra de cierre (o etiqueta de fin). La etiqueta de inicio se compone de un carácter menor que (<), un identificador_etiqueta_inicio que es un simple identificador y debe respetar las restricciones de los identificadores; seguido por cero o más parejas atributo="valor"; y un carácter de mayor que (>).

La etiqueta de cierre o etiqueta de fin consta de los caracteres menor que (<) y un slash (/), luego un identificador_etiqueta_cierre que obligatoriamente debe ser el mismo identificador que el de la etiqueta de inicio del elemento y un carácter de mayor que (>). La etiqueta de cierre nunca tiene atributos.

El contenido del elemento puede ser nulo o texto XML, es decir, datos de carácter, otros elementos (y por ende etiquetas) o ambos. Si un elemento no tiene contenido se dice que es un elemento vacío, y se puede escribir en cualquiera de las dos siguientes formas:



]]>

La segunda de las formas anteriores consta de una sola etiqueta llamada etiqueta vacía, la cual finaliza en un slash (/) indicando que el elemento ha terminado. Es poco común encontrar etiquetas vacías sin atributos.

Un elemento vacío no puede tener ninguna forma de contenido, ni siquiera espacios en blanco o cambios de línea. Es decir, que si en la primera forma de las listadas anteriormente se incluyera un cambio de línea, se consideraría como un dato de carácter y ese sería el contenido del elemento. Por el contrario, si un elemento tiene contenido (no es vacío) y se omite alguna de las etiquetas (la de inicio o la de fin) el procesador XML deberá alertar de que el documento no está bien formado.

Debe quedar claro que las etiquetas no son elementos. Las etiquetas inician con un '<' y terminan con un '>', lo demás no son etiquetas [Gold99]. Los elementos tienen etiquetas y contenido. Los elementos se escriben en el documento XML y son instancias de los tipos de elementos, los cuales se declaran en la definición del tipo de documento (DTD).

Atributos

Los elementos pueden tener atributos que son "una forma de incorporar características o propiedades a los elementos de un documento" [Gold99, 353]. Los atributos se escriben en la etiqueta de inicio. Un atributo se compone de un identificador, un signo de igual (=) y un valor entre comillas dobles, simples o una combinación de ambas; siempre que la comilla que cierra sea del mismo tipo de la que abre.

content
]]>

Cuando se crea un nuevo tipo de documento, es difícil decidir qué representar con elementos y qué con atributos. Las siguientes diferencias pueden ayudar en la decisión. Más adelante se retomaráne estas diferencias a un nivel más formal.

  1. Un elemento puede tener varios elementos hijos del mismo tipo, por lo que pueden representar partes del documento que se repiten. Un atributo no puede repetirse un elemento.
  2. Se puede controlar el orden de aparición de los elementos, mientras que los atributos pueden aparecer en cualquier orden.
  3. Los elementos pueden tener estructura, como elementos hijos de distinta naturaleza. Los atributos son pequeños textos o números.
  4. Los elementos tienden a ser visibles a los lectores o consumidores del documento, los atributos tienden a estar ocultos.
20 pts.

Asuma que los activos de su sistema de inventario se relacionan jerárquicamente. Por ejemplo, un inventario para la Escuela de Computación estaría compuesto de un edificio, el cual tiene tiene salas, las salas contienen escritorios, pizarras, teléfonos, computadoras, etc; una computadora tiene procesadores, módulos de memoria RAM, discos duros, y así por el estilo. El cliente necesita además distinguir cuáles activos son fijos y cuáles no; la condición de cada activo (en funcionamiento u ocioso); el estado del activo (buen estado, defectuoso, dañado); y la posibilidad de escribir detalles, que es un texto de cualquier longitud.

La figura fig_xml_inventory muestra un ejemplo de un inventario hipotético. Los rectángulos a la izquierda representan los activos y las flechas hacia la derecha indican los responsables de cada activo. Represente en su documento XML la jerarquía de activos mostrada en esta figura. Sus elementos deben ser genéricos, de tal forma que puedan reutilizarse para inventarios de cualquier otra empresa. Sus elementos deben además contener atributos y deben asociarse reflejando la jerarquía natural del inventario. De ser posible, use identificadores en inglés para sus elementos y atributos.

Inventario de la Escuela de Computación
Inventario ficticio y reducido de nuestra escuela de computación (administración 2010-2013)
10 pts.

Su cliente necesita saber cuál o cuáles empleados están a cargo de un activo (identificados por cédula), qué rol cumplen en la empresa y tener una forma de comunicación con ellos (correo o teléfono). Represente en su documento XML los empleados de la fig_xml_inventory.

Si un activo no tiene encargados, se asume que son los mismos del activo que lo contiene; por ejemplo, los encargados del video beam VB54403 son los mismos que del laboratorio IF104. Esta característica debe reflejarse en su diseño, de tal forma que un activo podría no tener encargados declarados explícitamente. Note que existe una relación N:M entre los activos y los empleados. Para este ejercicio, usted no debe redundar los detalles de los empleados en cada activo a cargo.

Semántica de los elementos XML

Cuando se escribe un documento XML, el autor escoge los identificadores de los elementos, los atributos y la estructura a su gusto y la plasma en un DTD. Cuando una persona observa el marcado de un documento XML y se pregunta "¿qué significa esto?" o bien "¿qué aspecto tendrá después?", estará haciendo preguntas sobre su semántica. Por ejemplo, si se encuentra una etiqueta <T> esta podría indicar que se trata de un título, una tabla o alguna otra cosa [Gold99].

La computadora no puede inferir la semántica de un documento XML dado, sino que es responsabilidad del autor de la gramática describir esta semántica para que otros autores puedan comprenderlo. Esta descripción se puede realizar en un documento PDF (Portable Document Format), un libro, o cualquier otro medio de comunicación [Gold99]. Más adelante se hará en comentarios en el DTD.

Como señala Goldfarb, "lo que le interesa a la computadora es el aspecto que se supone debe tener un elemento cuando está formateado, la forma en que debe actuar si es interactivo o qué hacer después de extraer los datos. Estas cuestiones se encargan de especificarlas las hojas de estilo y los programas informáticos" [Gold99, 350].

Otras formas de marcado

Los elementos y atributos son las formas más comunes de marcado en el cuerpo del documento. Sin embargo, hay otras formas de marcado importantes: las entidades, las secciones CDATA, y los comentarios. También se considerarán en esta sección los espacios de nombres.

Entidades predefinidas

Una entidad XML es similar a una constante de un lenguaje de programación. Una constante tiene un nombre y un valor. Cada vez que se escribe el nombre de la constante, el compilador lo reemplaza por su valor. Una entidad XML es como una constante cuyo valor es cualquier trozo de texto: un carácter, un párrafo, un archivo (incluso binario), o todo un libro. A las entidades se les da nombre, y su valor se puede obtener mediante una referencia de entidad, con la notación &entidad;. Por ejemplo, &lt; en un documento XML es reemplazado por el símbolo "<". Aunque XML define muchos tipos de entidades, en este documento sólo se estudiarán las entidades predefinidas.

Las entidades predefinidas "son marcas que representan caracteres que de otro modo se interpretarían con un significado especial" [Gold99, 358], como los caracteres menor que (<) y ampersand (&). Existen cinco entidades predefinidas mostradas en la xml_predefined_entities. "Cuando el procesador XML analiza el documento, reemplaza las referencias de entidad por los caracteres reales", en lugar de interpretarlos como caracteres de marcado [Gold99, 359].

Referencia de entidad Valor
&amp; &
&lt; <
&gt; >
&apos; '
&quot; "
Entidades predefinidas en XML.

Nótese que las etiquetas se delimitan con paréntesis angulares ("<" y ">"), y las referencias a entidades entre el signo "&" y el punto y coma (";"). Se dice que el texto encerrado dentro de estos cuatro caracteres se conoce como marcado, lo restante como datos de carácter. La combinación del marcado más los datos de carácter forman el texto XML [Gold99].

10 pts.

Seleccione el texto del xml_eg_book e imprima la selección en papel. Utilizando dos resaltadores, distinga el marcado de los datos de carácter en el listado impreso. Agregue una leyenda indicando qué representa cada color. Escanee o tome una fotografía del resultado. Edite su imagen, especialmente sus dimensiones, para que ocupe poco espacio (menos de 200kB) en un formato de compresión de imágenes (por ejemplo, JPEG). Agregue su imagen a su repositorio de control de versiones.

Secciones CDATA

Aunque el uso de entidades predefinidas parece sencillo, hace que el documento XML se vuelva difícil de leer para el autor, en especial cuando se usan repetidamente, como ocurre al escribir segmentos de código fuente; por eso se crearon las secciones CDATA. Estas secciones indican al procesador XML que no interprete una parte del texto aunque contenga marcado, es decir, que lo trate como datos de carácter (character data, de ahí la contracción CDATA). La sintaxis de una sección de datos de carácter es

<![CDATA[ contenido ]]>

En el contenido puede aparecer cualquier cadena de texto, excepto la que cierra la sección CDATA (]]>) llamada CDEnd. La línea 29 del xml_eg_book usa dos entidades preestablecidas. Este mismo elemento pudo haberse escrito con una sección CDATA como

<p><![CDATA[
   Su popularidad puede deberse a su "facilidad de uso" y...
]]></p>

Comentarios

Los comentarios son cadenas de caracteres que no son parte de los datos de carácter, es decir, es parte del marcado pero que debe ser ignorado por el procesador XML. Permiten al autor hacer anotaciones que le ayuden a comprender o recordar partes del documento. El texto del comentario se introduce entre los caracteres inicio de comentario (<!--) y final de comentario (-->). Por ejemplo

]]>

Todo el texto dentro del inicio y fin de comentario será ignorado, incluyendo los caracteres de marcado (menor que, mayor que, ampersand-punto y coma), excepto la secuencia de cierre del comentario (-->). Para algunos procesadores XML, la secuencia de dos giones (--) es prohibida dentro de un comentario. Aunque no es obligatorio, se recomienda separar los dos guiones (--) del texto de los comentarios por un espacio en blanco, como se hizo anteriormente y no de la siguiente forma:

]]>
5 pts.

¿Está el siguiente documento XML bien formado? Si su respuesta es negativa, señale los errores y las líneas en que aparecen:




	
		¿A qué se refiere bootstrap del sistema operativo?
		
			
			
			
		
	
	<-- -------------------------------------------- -->
	
		¿Qué fenómeno del OS representan los filósofos comensales?
	

]]>
¿Está este documento XML bien formado? Obtener archivo.

Espacios de nombres (namespaces) [tema opcional]

Es natural querer combinar diferentes tipos de documentos. Por ejemplo, en una presentación incluir una fórmula o un gráfico, o en un documento incluir una hoja de cálculo. Si un documento XML se incrusta dentro de otro, y ambos utilizan un mismo identificador con propósitos distintos, habrá una colisión de nombres. Por ejemplo, el documento web del xml_eg_name_collision tiene una figura SVG incrustada entre las líneas 8 a 15. Ocurre una colisión con los elementos <a>: el de la línea 9 pertenece a la imagen SVG y el de la línea 17 pertenece a XHTML.






	

Dado un triángulo cualquiera:

a b c

Se puede calcular su área con la fórmula de Herón:

s = sqrt(s(s-a)(s-b)(s-c)), s = (a+b+c)/2

]]>
Ejemplo de una colisión de nombres (el elemento <a>) Obtener archivo.

Para evitar colisiones se utilizan espacios de nombres (namespaces). Los espacios de nombres permiten distinguir los elementos que pertenecen a un tipo de documento de los que pertenecen a otro tipo de documento (llamados vocabularios). Los espacios de nombres distinguen los elementos de diferentes vocabularios agregando un prefijo a los identificadores de los elementos, de la forma Prefijo:NombreElemento. El xml_eg_namespace_2 distingue el vocabulario al que pertenecen todos los elementos del documento.






	Dado un triángulo cualquiera:
	
		
			
				
			
			a
			b
			c
		
	
	Se puede calcular su área con la fórmula de Herón:
	s = sqrt(s(s-a)(s-b)(s-c)), s = (a+b+c)/2


]]>
Todos los elementos de un documento y el espacio de nombres al que pertenecen Obtener archivo.

En el xml_eg_namespace_2 se dice explícitamente a qué vocabulario o espacio de nombres pertenece cada elemento del documento. Se usó el prefijo h para identificar a los elementos que pertenencen a XHTML y el prefijo s para aquellos que pertenecen a SVG. Estos prefijos se definen con el atributo xmlns, que es una contracción de xml namespace. Recuerde que los atributos que inician con xml están reservados por el estándar.

Todos los elementos XML tienen un atributo xmlns implícito. Cuando el autor lo hace explícito, define un espacio de nombres de la forma: xmlns:Prefijo="URL". El Prefijo es sólo un identificador de uso interno en el documento. El elemento donde aparece el atributo xmlns y todos sus hijos pueden utilizar el Prefijo para hacer explícito el espacio de nombres al que pertenencen. Es decir, el elemento y sus hijos pueden utilizar la notación Prefijo:Elemento en sus etiquetas de inicio y de cierre. Se usa un URL para identificar al espacio de nombres de forma única. El URL no es necesario que exista, pues el procesador XML no lo consulta. Sólo se debe usar consistentemente para identificar al espacio de nombres y evitar que colisione con espacios de nombres definidos por otros usuarios.

Se pueden definir tantos prefijos como vocabularios se usen en el documento. En el xml_eg_namespace_2 se definieron dos prefijos: h y s, ambos en el elemento raíz html de la línea 4. Por tanto el atributo xmlns puede repetirse porque el prefijo pasa a ser parte del nombre del atributo, y también del nombre de los elementos que lo utilicen. Con el uso de ambos espacios de nombres en el xml_eg_namespace_2, es claro para un software XML distinguir que el elemento a de la línea 9 es un enlace SVG, y que el elemento a de la línea 17 es un enlace HTML.

Si al definir un espacio de nombres con el atributo xmlns se omite el prefijo, se estará indicando el espacio de nombres global. Todos los elementos hijos que no expliciten un prefijo, pertenecen al espacio global. En la línea 4 del xml_eg_namespace_3 se indica que el espacio de nombres global es XHTML, a excepción de los elementos que inician con el prefijo s, pues son elementos SVG. El espacio de nombres s se definió en el elemento svg de la línea 8, pero es más usual hacerlo en el elemento raíz (en este caso, html, de la línea 4). Este ejemplo muestra otro detalle. Los enlaces a de SVG usan el estándar XLink, el cual requiere su propio espacio de nombres (línea 9).






	

Dado un triángulo cualquiera:

a b c

Se puede calcular su área con la fórmula de Herón:

s = sqrt(s(s-a)(s-b)(s-c)), s = (a+b+c)/2

]]>
Define el espacio de nombres global como XHTML, y el espacio de nombres s como SVG. Obtener archivo.

La definición del tipo de documento (DTD)

La definición de tipo de documento (DTD, Document Type Definition) es "el conjunto de normas XML para la representación de documentos de un determinado tipo" [Gold99, 49]. En pocas palabras, el DTD describe la gramática del documento [W3C00], es decir, los tipos de elementos, sus atributos, entidades, algunas restricciones y cómo se relacionan entre ellos. Esta sección explica la sintaxis que XML utiliza para representar estos conceptos y sus relaciones en un DTD.

Un documento XML que respete cabalmente las reglas establecidas en su DTD se dice que es válido. A modo de ejemplo, el xml_dtd_book muestra el DTD referido en el libro del xml_eg_book llamado book.dtd.


































]]>
Ejemplo de una definición de tipo de documento (DTD) para representar libros.

Declaraciones de tipo de elemento

Entre otras cosas, en el DTD se escriben las declaraciones de tipo de elemento que son restricciones que deben respetar todos los elementos en un documento XML válido. Estas declaraciones tienen la siguiente sintaxis

]]>

El <!ELEMENT inicia la declaración de un tipo de elemento. El IdElemento es el identificador que aparece en sus etiquetas. Debe ser único en el DTD y respetar las restricciones de los identificadores XML. La EspecContenido se refiere a la especificación de contenido, que indica qué objetos pueden figurar en el contenido del elemento, hay cuatro posibilidades [Gold99]:

Especificación de contenido de elementos XML.
Tipo Descripción
EMPTY Impide que el elemento tenga contenido y por tanto sus etiquetas son vacías. Ejemplo: front-cover en la línea 22 en el DTD del xml_dtd_book.
ANY Puede contener cualquier elemento o carácter, lo cual no se recomienda ya que no es estructurado. Pueden ser útiles cuando se está escribiendo el DTD para lograr que los documentos sean válidos mientras se está refinando dicho DTD.
element-content Sólo puede contener los subelementos listados dentro de paréntesis en la especificación de contenido. Por ejemplo, la línea 26 del xml_dtd_book indica que los elementos chapter sólo pueden tener un título opcional y varios párrafos o secciones.
mixed-content Permite al elemento contener subelementos, datos de carácter (#PCDATA) o ambos, como ocurre con el elemento de párrafo p en la línea 31 del xml_dtd_book.

Cuando un elemento tiene subelementos (o elementos hijos) en el contenido (últimos dos casos de la lista anterior), es necesario especificar un modelo de contenido (content model), que establece el orden y número de apariciones de los subelementos.

El orden de los elementos hijos se establece con los caracteres coma, barra vertical (|) y paréntesis. Una secuencia de subelementos separados por coma indica que tales subelementos deben aparecer y en el mismo orden. La barra vertical indica que debe aparecer sólo uno de los dos subelementos que están en sus extremos. Los paréntesis agrupan partículas de contenido que son tratadas como unidades por los operadores anteriores, lo que permite combinarlos.

El número de apariciones de los subelementos se especifica con los indicadores de frecuencia que se escriben al final del subelemento, sin espacios en blanco y son tres. El signo de interrogación (?) indica que el elemento hijo es opcional, es decir, puede o no puede aparecer. El asterisco (*) indica que el subelemento puede aparecer 0 ó más veces (opcional y repetible). El signo de más (+) indica que el subelemento debe aparecer 1 o más veces (necesario y repetible) [Gold99].

15 pts.

Escriba la definición de tipo de documento para su inventario, es decir un archivo DTD en la misma carpeta donde se encuentra su inventario xml. Escriba en su DTD una declaración de tipo de elemento por cada uno de los que componen su inventario XML. Su especificación de contenido debe permitir jerarquías de activos de cualquier nivel de profundidad. Es decir, los activos deben poderse anidar.

10 pts.

Utilice comentarios en su DTD para explicar a un lector que esté empleando su especificación, qué significa cada elemento y sus atributos.

Declaraciones de la lista de atributos

Los atributos "son una forma de incorporar características o propiedades a los elementos de un documento" [Gold99, 353]. Un elemento puede tener una lista de atributos, la cual se declara en el DTD en la sección conocida como declaración de lista de atributos, usualmente después de la declaración del tipo de elemento. Tiene la siguiente sintaxis

]]>

El <!ATTLIST indica que se va a declarar la lista de atributos del elemento identificado por IdElemento. Los atributos continúan uno tras otro separados por espacios en blanco, sin impotar si son cambios de línea o no. Cada declaración de atributo se compone de un identificador (IdAttN), el tipo de datos (TipoAttN), y el valor por defecto (DefaultValueN). IdAttN indica el nombre del atributo; debe ser un identificador válido y no es obligatorio que sea único en el documento. El tipo del atributo TipoAttN puede ser alguno de los siguientes

Tipos de atributos en un DTD.
Tipo Descripción
CDATA Datos de carácter. Permite casi cualquier cadena de caracteres.
NMTOKEN Name token. Sólo permite letras, números y algunos caracteres especiales, como los que se utilizan para declarar identificadores, pero no obliga a que sea único en el documento.
NMTOKENS Una lista de name tokens.
(a|b|c|d) Enumerados. El atributo sólo puede tomar uno de los valores indicados en la lista dentro de paréntesis, los cuales se separan por barras verticales (|); por ejemplo el atributo type en la línea 29 del xml_dtd_book.
ID Identificador. Declara que el atributo es un identificador único, es decir, su valor debe cumplir con las restricciones de los identificadores y en el documento XML no puede haber dos o más atributos con el mismo valor.
IDREF Referencia a un identificador. Declara que el atributo tiene como valor una referencia a un identificador existente. Su valor puede repetirse muchas veces en el documento XML pero debe respetar las restricciones de los identificadores.
ENTITY Referencia a una entidad (o atributos de entidad). El valor del atributo debe ser el nombre de una entidad existente en el documento XML.

El DefaultValueN en la declaración de la lista de atributos indica si el atributo se puede omitir o no, y el valor por defecto en caso de que se omita. Puede tomar tres variantes:

Valores por defecto de atributos en un DTD.
Tipo Descripción
#REQUIRED Indica que el atributo es requerido y no se puede omitir, por tanto no tiene un valor por defecto. Son ejemplos name y version de book en el xml_dtd_book.
value Un valor que está en el dominio de valores permitido por el tipo de atributo. Indica que ese será el valor que el procesador XML tome si el autor no especifica uno en el documento. Por ejemplo, según la línea 29 del xml_dtd_book, si el autor no especifica el tipo del capítulo, el procesador XML asumirá que se trata de un capítulo de contenido y no uno preliminar.
#IMPLIED Permite al autor omitir el valor del atributo pero sin forzar a escribir un valor por defecto determinado. El procesador XML asignará algún valor que considere adecuado o lo ignora.
10 pts.

Para cada elemento que recibe atributos, escriba en su archivo DTD una declaración de lista de atributos. Trate de usar atributos identificadores (ID) y valores enumerados (a|b|c|d) siempre que sea posible. Al menos debe hacerlo en los dos siguientes casos:

  • Utilice valores por defecto, de tal forma que el sistema pueda asumir los valores más comunes para algunos atributos de los activos, lo cual ahorra memoria en el documento XML y hace más rápido el procesamiento (parsing) del mismo.
  • Obligue al analizador XML (XML parser) a considerar como no válido, un inventario que contenga activos a cargo de empleados que no existen en la compañía.
10 pts.

Asegúrese de que su documento XML es válido ante el DTD que escribió. Utilice un analizador XML genérico (XML parser). A modo de sugerencia puede emplear el Gnome XML C parser. Si utiliza alguna distribución de Linux instale el paquete libxml2-utils, y emita el comando

xmllint --valid --noout /path/to/file.xml

Si su documento XML es válido, el comando anterior no generará salida en pantalla. Si utiliza Windows, puede descargar los binarios provistos por Igor Zlatkovic, descomprimirlos y mover los archivos de las subcarpetas bin\ a una carpeta incluida en su variable ambiente %PATH%. Luego puede utilizar una línea de comandos para emitir el comando previo, o si trabaja con Notepad++ instalar el XML Tools Plugin, el cual agregará opciones de menú para validar desde el editor.

Elementos versus atributos

No es trivial decidir qué aspectos del mundo real deben modelarse como elementos y cuáles como atributos. Tampoco existe un diseño mejor que otro. El autor debe escoger alguna convención que sea coherente y escribir un DTD para obligar a todos los documentos del mismo tipo a cumplir con el diseño escogido. Aunque no hay ninguna regla para decidir qué debe modelarse como un elemento o un atributo, Goldfarb sugiere las siguientes ideas.

Los atributos no pueden contener "subatributos" ni elementos, sino que son pequeños trozos de texto sin estructura o listas de condiciones. Por tanto, si algo del mundo real contiene otras partes que también deben modelarse, debe hacerse con elementos y no con atributos. Los atributos se usan para añadir poca información, sencilla y sin estructura [Gold99].

Los elementos deben respetar el orden y el número de ocurrencias descritos en el DTD, mientras que los atributos pueden aparecer en cualquier orden y no pueden repetirse. Por esto, las "cosas" que deben repetirse o que respetan cierto orden deben modelarse como elementos y no como atributos [Gold99].

Si las ideas anteriores no son criterio suficiente, puede usarse la siguiente heurística. Los elementos se utilizan para representar partes de los objetos, o datos que son parte del contenido principal, y deben aparecer en todas las impresiones o interpretaciones del documento. Los atributos se utilizan para representar propiedades de los objetos, es decir, información sobre los datos reales (metadatos) y que no necesariamente debe imprimirse [Gold99].

25 pts.

Su especificación para representar inventarios debe ser genérica. Es decir, muchas empresas de distinta naturaleza podrían utilizar su notación para representar sus respectivos inventarios, y su DTD debe ser capaz de representarlos sin tener que incluirle modificaciones. De esta forma, usted puede publicar su DTD en algún servidor web y quienes empleen su especificación, incluirían el DTD oficial en sus documentos XML (tal como ocurre con el DTD de XHTML, por ejemplo).

Para probar la generalidad de su DTD, cree otro documento XML y represente el inventario de la fig_xml_inventory_transp. Verifique que su documento es válido ante su DTD.

Inventario de una compañía de transportes
Inventario reducido de una compañía hipotética de transportes

Entidades XML [tema opcional]

Las entidades "permiten al documento dividirse en varios objetos de almacenamiento y son herramientas importantes para volver a utilizar y mantener el texto... Una entidad es como una abreviatura y se utiliza como una forma corta de algunos textos. La abreviatura se llama nombre de la entidad y la forma larga contenido de la entidad. El contenido puede ser tan corto como un carácter o tan largo como un capítulo" [Gold99, 389].

Las entidades se utilizan con referencias de entidades, cuya sintaxis consiste en escribir el nombre de la entidad entre los caracteres ampersand (&) y punto y coma (;). Cuando el procesador XML encuentra una referencia de entidad, la reemplaza por el contenido de la misma, proceso conocido como inclusión. Las entidades se crean con declaraciones de entidad, con una de las dos siguientes notaciones, donde los corchetes indican opcional:


]]>

Hay tres criterios para clasificar entidades y por tanto, 8 combinaciones de las cuales 5 son válidas. Los criterios son

  • Analizables o no analizables
  • Internas o externas
  • Generales o parámetro

Las entidades cuyo contenido es texto XML que debe ser analizado por el procesador XML reciben el nombre de entidades analizables (parsed entities). Si el contenido de la entidad es código ajeno a XML (como imágenes o texto puro) que no debe analizarse, se denomina entidades no analizables. Las entidades no analizables terminan en NDATA seguido por un indicador del formato, como ocurre con cedula en el xml_entity_examples. Las entidades que no se declaran con NDATA son analizables.

Las entidades externas son aquellas cuyo contenido está en un recurso fuera de la declaración de la entidad, y por tanto debe proveerse un URL hacia ese recurso precedido por la palabra SYSTEM o PUBLIC, como ocurre con cap01 y cedula en el xml_entity_examples. Mientras que el contenido de las entidades internas está escrito en la misma declaración de la entidad entre comillas, como ocurre con adn y frase en el xml_entity_examples.

Reciben el nombre de entidades generales aquellas que se pueden referir en cualquier lugar del documento XML, como ocurre con &adn; del xml_entity_examples y las entidades predefinidas, como &amp; que son declaradas por el procesador XML. Las entidades que sólo se pueden referir dentro del DTD se conocen como entidades parámetro. Es decir, son de uso exclusivo del DTD y no se pueden referir desde el documento XML. Se declaran anteponiendo un % y se referir usando la notación %IdEntidad; en lugar de &IdEntidad; como ocurre con %SectionType; en las líneas 1 y 40 del xml_dtd_book.


no tienes una solución sos parte de lo que criticas">


]]>
Contenido de una página web hipotética

Los identificadores externos "hacen referencia a información que se encuentra fuera de la entidad en la que tienen lugar" [Gold99, p404]. Existen dos tipos, los identificadores de sistemas (SYSTEM) y los identificadores públicos (PUBLIC).

Los identificadores de sistemas utilizan la palabra clave SYSTEM y se refieren a un objeto por su localización utilizando un URI (Universal Resource Identifier). Pueden ser direcciones absolutas o relativas a la ubicación de la entidad documento que contiene el identificador. La siguiente declaración referencia el recurso "http://www.serv.com/dir/cap02.xml":

]]>

Los identificadores públicos utilizan nombres declarados públicamente para referirse a la información. Estos nombres deben ser únicos en el mundo. Tienen cuatro partes separadas por dos slash (//). La primera parte es un carácter de suma (+) si la organización que publica el recurso está registrada en el ISO, sino es un carácter de menos (-), lo cual ocurre con mayor frecuencia. La segunda parte es el dueño del recurso. La tercera parte es la descripción del recurso, que permite espacios en blanco. La última parte es el lenguaje en que está escrito el recurso [Marc00]. Los dos siguientes ejemplos de declaraciones de tipo de documento emplean identificadores públicos. El primero de ellos es ficticio.



]]>

Ejercicios finales

5 pts.

Investigue la diferencia entre un conjunto de caracteres (character set) y la codificación del texto (text enconding). ¿Cómo esto afecta a los documentos XML?

30 pts. Represente en un documento XML la base de datos Universidad cuyo estado se encuentra en las siguientes tablas y su estructura en el modelo entidad-relación de la fig_xml_udatabase.

Una base de datos Universidad
Una base de datos Universidad
Estudiante
Carné Nombre Promedio
a45891 Eliécer Montero 7.14
a98765 Yanet Arias 8.96
b10976 Anais Solano 8.30
Profesor
Cédula Nombre
109830876 Edgar Casasola
208431187 Maureen Murillo
135900821 Francisco Arroyo
110101101 Jeisson Hidalgo
Curso
Sigla Nombre Créditos
CI-1101 Programación I 4
CI-1201 Programación II 4
CI-1320 Redes de Computadoras I 5
CI-2413 Desarrollo de aplicaciones web 4
Requisito
Curso Requisito
CI-1201 CI-1101
CI-2413 CI-1201
CI-2413 CI-1320
Grupo
Curso Numero Anno Semestre Horario Aula Profesor
CI-1101 04 2011 1 KV13-15 301IF 109830876
CI-1101 08 2011 1 KV07-09 304IF 208431187
CI-1320 01 2011 1 KV17-19 303IF 135900821
CI-2413 01 2011 1 KV15-17 305IF 110101101
Matricula
Estudiante Curso Grupo
a45891 CI-1101 04
a45891 CI-1320 01
a98765 CI-1320 01
b10976 CI-2413 01
15 pts.

Escriba una definición de tipo de documento para representar la base de datos Universidad. Asegúrese de que el documento que escribió en el ejercio anterior sea válido ante este DTD.

10 pts.

Si no lo hizo, trate de desnormalizar las relaciones Requisito y Matricula en su documento XML de la base de datos Universidad. Es decir, estas relaciones no deben aparecer como una lista de elementos, sino como hijos de otros elementos. Actualice el DTD y asegúrese de que el nuevo documento XML sea también válido. ¿Se puede también desnormalizar la entidad débil Grupo?

El lenguaje de marcado de hipertexto (X)HTML

El lenguaje HTML nació como una aplicación SGML en 1991 y su mayor volumen de estandarización fue en la versión 4.0 de 1997. En 1998 el W3C publicó una simplificación de SGML llamada XML. En el 2000 el W3C publicó XHTML 1.0 como una adaptación de HTML sobre XML y actualizó HTML a 4.01 con el fin de que fuesen cercanamente compatibles. Después de ello, el W3C centró su atención en XHTML descontinuando HTML, hasta que un grupo independiente de interesados trabajaron en una especificación que se convertiría en (X)HTML5 compatible tanto con HTML 4.01 como XHTML 1.0.

El desarrollador web se puede estar preguntando cuál de estos dos lenguajes escoger para un sitio en que va a trabajar. Necesitará entender las diferencias para fundamentar su decisión. HTML es bastante liberal, mientras XHTML es inherentemente estricto. El xhtml_pure_html muestra un trozo de código HTML y el xhtml_pure_xhtml el mismo contenido en XHTML. Las principales diferencias entre estos dos lenguajes son las siguientes.

  1. Los identificadores en HTML no son sensitivos a mayúsculas ni minúsculas; mientras que en XHTML lo son y los definidos por la recomendación usan minúsculas consistentemente.
  2. HTML permite dejar elementos sin cerrar como p y li, otros nunca se cierran como br e img; mientras que en XHTML todo elemento debe cerrarse obligatoriamente.
  3. HTML permite minimizar atributos (attribute minimization), esto es, omitir las comillas alrededor de los valores de atributos que sólo contienen letras, números o los caracteres guión (-), punto (.), guión bajo (_) o dos puntos (:). XHTML exige que todo valor de atributo debe estar encerrado entre comillas.
  4. HTML permite que algunos atributos no tengan valor como disabled en <textarea disabled>, la presencia del atributo es suficiente para generar su efecto. XHTML exige que todo atributo tenga un valor entre comillas, y para estos casos, en XHTML el Consorcio Web tomó la convención de repetir el nombre del atributo en su valor, ejemplo: <textarea disabled="disabled"> [Cast06].
  5. Los elementos html, head y body son opcionales en HTML, pero obligatorios en XHTML. Sin embargo, es una mala práctica omitirlos en HTML.
  6. XHTML puede tener secciones CDATA, mientras que HTML no.



Mis libros

Compre uno de mis libros:

  • C++Ejercicios intrincados en C++
  • MateCómo ganarle al chofer de bus en mate
]]>
Un documento HTML 4.01 strict válido. Correr este ejemplo.





   
   Mis libros



   

Compre uno de mis libros:

  • C++Ejercicios intrincados en C++
  • MateCómo ganarle al chofer de bus en mate
]]>
Un documento XHTML 1.0 strict válido. Correr este ejemplo.

Es evidente que escribir HTML es más relajado que XHTML, si ambos producen el mismo efecto en el navegador ¿por qué molestarse con XHTML? HTML obliga al navegador a programar excepciones y reglas circunstanciales que dilatan el procesamiento y propician a la ambigüedad. XHTML obliga a una sintaxis restringida que facilita al navegador y otros software XML a interpretar código fácil y eficientemente. Además XML abre un conjunto de funcionalidades y tecnologías que no están disponibles para HTML, como la posibilidad de incrustar otras especificaciones como SVG y MathML en los documentos XHTML.

Si una persona piensa escribir algunas páginas manualmente, quizá HTML sea la mejor alternativa. Si planea que esas páginas formen parte de un sitio web grande, sean almacenadas en bases de datos o procesadas por algún tipo de software, es mejor que elija XHTML. En general se cumple que código XHTML válido es también código HTML válido (o con mínimas modificaciones), no el recíproco. Por eso este capítulo conferirá énfasis a XHTML y las diferencias importantes con HTML se resaltarán en su contexto.

10 pts.

El documento del convert_html_xhtml es HTML válido. Conviértalo en un documento XHTML 1.0 estricto válido. Revise la sección Declaración del tipo de documento para utilizar validadores automáticos.




Conversión HTML a XHTML

Conversión HTML a XHTML

  1. Cambie todos los identificadores a minúsculas.
  2. Asegúrese de que todos los elementos estén cerrados.
  3. Agregue comillas a todos los valores de atributos.
    Si hay atributos minimizados, repita su valor entre comillas.
  4. Agregue los elementos html, head y body si no lo están.

Conversión XHTML a HTML

  1. No cierre los elementos que se componen de sólo una etiqueta: img, br, hr, ...
  2. Si las hay, elimine las secciones CDATA y convierta los caracteres especiales (<, >, &) en sus respectivas referencias de entidad (&lt;, &gt;, &amp;).

]]>

Un documento HTML 4.01 strict válido. Correr este ejemplo.

Estructura global

Un documento web es muy similar a cualquier otro documento que una persona podría escribir en un procesador de palabras, y por ende tiene títulos, párrafos, tablas, imágenes, enlaces, estilos y otros elementos familiares. La principal diferencia es que un documento web debe seguir estrictamente la sintaxis de (X)HTML. Al hacerlo, cualquier software (X)HTML podrá manipular el documento, sea un navegador, un programa de diseño, un motor de bases de datos y hasta el mismo procesador de palabras mencionado anteriormente. Dado que el navegador es el más común, se usará en este texto por claridad en lugar de software (X)HTML.

Un documento web se compone de cuatro partes: la declaración del tipo de documento, el elemento documento, el encabezado y el cuerpo. El xhtml_outline muestra un ejemplo de documento XHTML con estas cuatro partes. Los comentarios utilizan la misma notación de XML y pueden aparecer en casi cualquier lugar del documento.






   
   Título del documento



   


]]>
Mínimo documento válido en XHTML 1.0

La declaración del tipo de documento web

La declaración del tipo de documento, expresada con la etiqueta <!DOCTYPE ...>, informa al navegador el tipo de documento (HTML o XHTML) y la versión usada en el resto del documento. Con esto el navegador sabrá cómo interpretar la sintaxis y contra cual especificación validar su código. La tabla html_doctypes muestra los tipos de documentos y sus versiones actualmente en uso. [Para una lista completa que incluye tipos de documentos para XHTML-Basic y XHTML Mobile Profile, resulta conveniente consultar la Wikipedia].

Language Ver. Variation Document type
HTML 4.01 strict <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
transitional <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
frameset <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN"
"http://www.w3.org/TR/html4/frameset.dtd">
XHTML 1.0 strict <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
transitional <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
frameset <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
1.1 -- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
(X)HTML 5.0 -- <!DOCTYPE html>
Tipos de documento (X)HTML de acuerdo a su versión y variación

Aunque en HTML es opcional, siempre es conveniente incluir el tipo de documento; y a menos de que se esté usando (X)HTML5 es difícil memorizarlos. Por eso los autores históricamente han tenido una fuente de la cual copiar y pegar los tipos de documentos en sus creaciones, o confiar en un programa de diseño web que haga el trabajo automáticamente.

Si se omite la declaración del tipo de documento, la mayoría de navegadores entran en "quirks mode", un modo de compatibilidad para poder desplegar páginas web obsoletas que contienen errores o "quirks", con resultados que eran dependientes del navegador. Si la declaración del tipo de documento está presente, el navegador entra en modo estándar, y si el documento es válido, el comportamiento debería ser homogéneo entre navegadores.

5 pts.

Descargue un DTD de HTML 4.01 ó XHTML 1.1 y averigüe si ¿es permitido escribir texto puro directamente en el contenido del elemento body? Justifique su respuesta.

Existen varias herramientas gratuitas de aseguramiento de la calidad (QA, Quality Assurance)que permiten someter un documento web a un conjunto de pruebas y obtener retroalimentación de si está bien formado, se conforma al tipo de documento que declara, no tiene enlaces rotos, sus estilos son válidos y otras pruebas. Algunas de estas herramientas son las siguientes:

Existen otros validadores disponibles no mencionados en la lista anterior. Un código que resulte ser válido tras someterse a varios validadores, se considerará de mejor calidad y con más garantía de funcionar apropiadamente entre navegadores.

5 pts.

Localice dos páginas web de su agrado y sométalas al validador del W3C. Al menos una de ella debe no conformarse al estándar que declara. Si usted tuviera que corregirla, describa rápidamente qué cambios tendría que hacerle.

10 pts.

Haga estadísticas. Someta al validador del W3C al menos diez páginas web que frecuenta (por ejemplo, las que tiene registradas en sus favoritos). ¿Cuántas de ellas son válidas? ¿Qué tipos de documentos (DTD) son los menos y más usados? ¿Reflejan sus resultados estadísticas generadas por otros autores (por ejemplo: 70% HTML, 30% XHTML)?

Cuando escriba un documento HTML, almacénelo con extensión .html y los documentos XHTML con extensión .xhtml. Aunque la extensión no debería ser algo de importancia, de forma lamentable, la mayoría del software web actual se guía por este detalle en lugar de la declaración del tipo de documento (incluso los validadores del W3C). Es probable que se tenga que hacer ajustes en la configuración del servidor web para que sirva los archivos XHTML correctamente. Además Internet Explorer 8 y anteriores no despliegan páginas XHTML sino que las ofrecen al usuario para que las guarde en disco; lo cual es una muestra de la reluctancia de Microsoft por los estándares.

(X)HTML5 pretende simplificar el web de un modo pragmático. Aunque aquí se incluye el "5" en "(X)HTML5" para diferenciarlo de sus predecesores, sus autores lo llaman realmente HTML, el estándar vivo, sin ningún número de versión, y por eso no se especifica en el DOCTYPE, ni tampoco su DTD como se aprecia en la línea 1 del xhtml5_outline, lo cual hace que deje de ser una aplicación XML válida. Por esto se dice que XHTML5 no existe como un estándar. El estándar es HTML5, el cual permite utilizar tanto la notación de HTML como XML, pero sin mezclarlos. Por esto XHTML5 no es una aplicación XML como sí lo es XHTML 1.0. XHTML5 simplemente es un término para referirse al HTML5 que utiliza notación XML.

Dado que XHTML5 no es una aplicación XML, los navegadores ignorarán la declaración XML (<?xml ...?>) en la primera línea del documento, por lo cual es común omitirla, como se hizo en el xhtml5_outline. La declaración de codificación debe hacerse entonces en el encabezado con un elemento meta (línea 4) mucho más sencilla que en XHTML 1.0 (compárese con la línea 7 del xhtml_outline).



   
      
      Título del documento
   
   
      
   

]]>
Mínimo documento válido en XHTML5. Ver archivo.

El elemento documento

El elemento documento o elemento raíz de un documento (X)HTML es html. Normalmente se escribe sin atributos, lo cual es válido tanto en HTML como XHTML. Su único atributo exclusivo en XHTML es el espacio de nombres xmlns, el cual sirve para indicar que sus identificadores pertenecen al espacio de nombres de XHTML y así evitar que colisionen con otras especificaciones. Los demás atributos son los comunes para casi todos los elementos XHTML, mostrados en la xhtml_common_att. El elemento raíz html sólo admite dos elementos hijos: un encabezado (head) y el cuerpo del documento (body).

Atributo Descripción
id Un nombre que identifica de forma única a un elemento, de tal forma que se le puede hacer referencia posteriomente, en especial en hojas de estilo y programas de JavaScript.
class Sirve para agrupar varios elementos bajo un identificador común. A todos los elementos de una misma clase se les puede aplicar estilos o acceder desde un programa de JavaScript. Por su parte, un elemento puede pertenecer a varias clases, las cuales se separan por espacios en blanco en el valor de este atributo.
xml:lang Indica el idioma en el que se encuentra el contenido del elemento. Su valor es un código de idioma en el estándar ISO-639. Sólo está disponible en XHTML. Tiene prioridad sobre lang.
lang Igual que xml:lang. Está disponible tanto en HTML como XHTML, por lo que se prefiere en (X)HTML5.
dir La dirección del texto que se encuentra en el contenido del elemento. Puede tomar tomar los valores ltr para izquierda a derecha y rlt para derecha a izquierda.
Atributos comunes para la mayoría de elementos (X)HTML
5 pts.

Obtenga una copia del archivo que hizo en el ejercicio html_to_xhtml. Cambie la dirección del texto de derecha a izquierda del elemento body u otros elementos. Pruebe en un navegador su efecto. ¿Es lo mismo que usar el estilo de justificación derecha del texto?

Encabezado del documento

El encabezado del documento (X)HTML contiene información sobre el documento mismo pero que no es considerado parte del contenido, a lo que frecuentemente se le llama "metadatos" y son útiles para los navegadores o motores de búsqueda. Los elementos que pueden aparecer en el encabezado son: el título del documento, metadatos, hojas de estilo, programas de JavaScript y otros objetos. En esta sección se estudiarán los dos primeros.

El título del documento se escribe como un texto simple en el contenido del elemento title y es obligatorio en XHTML. No es parte del contenido del documento porque las personas lo usarán antes de tener acceso a él. Por eso, es uno de los textos más importantes y siempre debe escogerse con cuidado, tratando de que sea corto y descriptivo. Aparece en la barra de título del navegador y en los resultados de los motores de búsqueda como Google y Yahoo. Los lectores lo verán en el historial de su navegador y con suerte en sus favoritos.

Los metadatos son detalles sobre el contenido del documento como el autor, palabras clave, codificación del texto, etc. Se escriben en forma de parejas atributo-valor con el elemento vacío meta. El nombre del metadato se escribe en el atributo name y el valor del metadato en el atributo content. Si el nombre del atributo es el mismo que una de las directivas del encabezado HTTP se puede escribir en el atributo http-equiv en lugar de name. Cuando un documento web es solicitado, el servidor web puede revisar el encabezado por estos metadatos http-equiv y agregar las respectivas directivas en el encabezado del mensaje de respuesta HTTP (HTTP Response header) que precede al documento.

La recomendación (X)HTML no define un conjunto de valores válidos para ninguno de los atributos de meta, sino que permite libremente construir perfiles (profiles) de metadatos. El xhtml_header_example muestra un ejemplo de encabezado con título y metadatos comunes en XHTML 1.0. Para más detalles, revísese la especificación HTML 4.01. En versiones más recientes de (X)HTML, el W3C ha adoptado una notación más elaborada para la especificación de metadatos llamada Marco de descripción de recursos (RDF, Resource Description Framework).


   
   
   
   
   Carta al estudiante

]]>
Encabezado de un documento XHTML 1.0 con metainformación y título

El metadato para declarar la codificación del documento (en la línea 2 del xhtml_header_example) es tan común que en (X)HTML5 se agregó el atributo charset [que conceptualmente debió llamarse encoding] al elemento meta. De esta forma, los documentos (X)HTML5 pueden especificar la codificación de la forma compacta <meta charset="utf-8"/>, como se hizo en la línea 4 del xhtml5_outline.

5 pts.

Nota: Para la serie de ejercicios identificados de la forma website_index_#, no cree una carpeta, sino un archivo index.html en la raíz de su sitio web personal. Cada ejercicio en esta secuencia debe generar un commit con cambios en este archivo.

Cree un archivo index.html en la raíz de su sitio web personal. Su documento debe ser HTML5 con el espacio de nombres XHTML y apegarse a la nomenclatura XML. Escriba el encabezado HTML. Su encabezado debe tener un título significativo y al menos los siguientes metadatos: codificación, autor, el generador (quién hizo el documento: usted mismo/a) y palabras clave. Puede revisar la recomendación HTML5 por documentación sobre estos metadatos.

Después del encabezado (elemento head) continúa el cuerpo del documento (elemento body). El cuerpo del documento almacena el contenido del documento. Esto es lo que ve o escucha el usuario una vez que se ha cargado. El contenido del elemento body puede ser texto puro en HTML, pero normalmente es una mezcla de los elementos que se explican en el resto de secciones de este capítulo.

Elementos de estructura del documento

Un sitio web es una colección intercomunicada de páginas web. Para hacer que la interacción de los visitantes con el sitio sea clara, todas las páginas que componen el sitio deben tener la misma estructura principal, presentación y comportamiento. La estructura principal de la página se refiere a las grandes partes o secciones de información que la componen. En la mayoría de sitios web, estas grandes partes son un encabezado del sitio, un pie de página, un menú de navegación y el contenido propio de cada página. La fig_xhtml_site_structure muestra estas partes rotuladas en verde y dos distribuciones en que se pueden formatear con hojas de estilo.

Estructura de página web
Una estructura de página y dos formas de distribuir sus partes con estilos

(X)HTML5 define elementos para describir cada una de las partes mencionadas. Los autores de versiones previas de (X)HTML utilizaron elementos genéricos (div), los cuales siguen siendo válidos en (X)HTML5, pero carentes de semántica. El xhtml_page_structure_outline presenta un ejemplo de cómo se pueden utilizar los nuevos elementos en (X)HTML5 para especificar la estructura principal de página de inicio de un sitio web. En la siguiente subsección se explica cada uno de estos elementos.




	
	
	Título de la página


	
	
	
...
...
...
...
...
]]>
Estructura general en XHTML5 de una página característica de un sitio web. Correr este ejemplo.

Debe aclararse que un sitio web está compuesto de páginas web. Si se quiere que la estructura principal, la presentación y el comportamiento sea uniforme en todo el sitio web, cada página que compone el sitio debe tener la misma estructura principal, reglas de estilo y código de JavaScript. Esto lleva a redundancia de código. Los estándares web permiten reutilizar hojas de estilo y archivos de JavaScript a lo largo de todo el sitio; pero no proveen un mecanismo natural para reutilizar contenido (como el encabezado o pie de página del sitio web). Por esto los autores deben recurrir a otras tecnologías para evitar la redundancia de código no controlada. Ejemplos de estas tecnologías son Server Side Includes, programación del lado del servidor (como PHP), documentos anidados (iframe), o programación del lado del cliente (JavaScript). En el capítulo sobre programación del lado del servidor se construirá un web framework minimalista para resolver este problema.

Elementos de estructura en (X)HTML5

En un sitio web puede haber publicaciones de diversa naturaleza y de distintos autores: artículos, entradas de un blog, comentarios enviados por los lectores, libros, tutoriales, encuestas, noticias, etc. Para representar estas creaciones (X)HTML5 define seis elementos genéricos para amoldarse y poder describir la estructura de un documento: header, footer, nav, aside, article y section.

En (X)HTML5 el elemento header sirve para describir el encabezado de página, de un artículo o una sección. En cuanto a un sitio web, el encabezado suele contener el logotipo de la empresa o del sitio, el título del sitio, algún lema, y un campo de texto para hacer búsquedas en el sitio web, entre otros elementos. En las líneas 10 a 14 del xhtml_page_structure se muestra un encabezado de sitio web. El sobreuso que se hizo en el xhtml_page_structure del atributo id en la mayoría de elementos de estructura es opcional, pero facilita la labor de presentación (hojas de estilo) y de comportamiento (JavaScript).

El elemento footer indica el pie de página, o el pie de una sección; el cual sirve para indicar información acerca de ella, como el autor, enlaces hacia documentos relacionados (como términos de servicio, u otro menú de navegación), derechos de autor, etc. Las líneas 54 a 56 del xhtml_page_structure presentan un pie de página, cuyo texto se escribió dentro de un elemento small, redefinido en (X)HTML5 para marcar textos con restricciones legales y similares.

El elemento nav sirve para indicar un conjunto de enlaces que proveen navegación de la página misma (como una tabla de contenidos), o del sitio web mismo, como se hizo en las líneas 16 a 25 del xhtml_page_structure. Enlaces de publicidad, referencias bibliográficas, resultados de búsquedas, y similares, no deben encerrarse dentro de un elemento nav, dado a que no representan navegación dentro del sitio. El elemento nav puede contener títulos; cero, una o varias listas no ordenadas; párrafos y otros elementos.

El contenido de la página web inicia con cualquier elemento que no sea uno de los anteriores. Sin embargo, es apremiante que el autor estructure el contenido utilizando elementos article y section.

De acuerdo a la especificación oficial, el elemento article se utiliza para especificar una obra auto-contenida en un documento, página, aplicación o sitio; y es, en principio, independientemente "distribuible" o reutilizable [Laws11]. Esto implica que un artículo es un trozo de información que puede ser movido de un lugar a otro dentro de la misma página web (a un margen, por ejemplo) y mantener su sentido. Son ejemplos: una entrada de un blog o foro, una noticia, un comentario de usuario, etc. Los elementos article se pueden anidar. En el xhtml_page_structure se indicó que la página web completa es un artículo (línea 9 a 57) y el contenido propio de la página, es decir, sin considerar el encabezado, menú de navegación y pie de página, es también un artículo (línea 27 a 52).

Los artículos se dividen en secciones temáticas. Por ejemplo, un libro se divide en partes, capítulos y secciones. Cada una de estas partes se identifica con un título. El elemento section permite dividir un artículo en partes o secciones, las cuales no son independientes, sino que tienen un orden. Como es de esperar, si una sección de contenido se mueve de lugar dentro de la misma página web (a un margen, por ejemplo), perderá su sentido. En el xhtml_page_structure cada entrada introductoria hacia una parte del sitio web, fue representada como una sección (líneas 34 a 40, y líneas 42 a 48). Las secciones se pueden anidar entre sí. La especificación (X)HTML5 también permite anidar artículos dentro de secciones; y las secciones también pueden tener encabezados, elementos de navegación y pie de sección.

El elemento aside sirve para indicar contenido que no es considerado parte del contenido principal del documento, por ejemplo, publicidad, noticias, artículos relacionados, etc. Si se quiere, el menú de navegación del sitio (nav) puede escribirse dentro de un elemento aside, para indicar que no es parte del contenido principal.




   
   
   Tres uves dobles


   

Bienvenido(a) a Tres uves dobles, un sitio web con consejos para crear sitios web. Todo el código aquí alojado puede utilizarlo libremente en sus propios proyectos. Además puede colaborar con nuevos trucos que considere útiles para otros desarrolladores. Los consejos en este sitio están separados en los siguientes grandes temas:

Sección XML

Trucos sobre XML

Trucos para representar información en XML. Escribir y documentar sus propios DTD. Hacer transformaciones con XSLT. Formatear documentos con XSL-FO. Ejemplos de API y DOM.

Sección (X)HTML

Trucos sobre (X)HTML

Trucos para representar contenido en HTML 4.01, XHTML 1.0 y (X)HTML5. Tipos de documento. Elementos de texto. Elementos de estructura. Elementos multimedia (imágenes, audio, vídeo).

© 2012. Jeisson Hidalgo-Céspedes. Todos los derechos reservados.

]]>
Estructura en XHTML5 de una página principal de un sitio web ficticio. Correr este ejemplo.
5 pts.

Identifique las partes o secciones de contenido que su sitio web personal debe tener, a partir del diseño de sitio que realizó en el ejercicio [student_site_design]. Refleje estas partes o secciones en su índice del sitio web (index.html) utilizando los elementos de estructura definidos en (X)HTML5.

Elementos genéricos de estructura

Cuando el autor quiere especificar la estructura de un trozo de información, pero no existe un elemento en el estándar (X)HTML para tal fin, debe recurrir a uno de los elementos genéricos: div o span. Nota: Los autores deben siempre preferir los elementos semánticos y recurrir a los elementos genéricos sólo en última circunstancia, cuando no existe un elemento para el fin requerido.

Según la recomendación, el elemento div carece completamente de semántica. Simplemente se utiliza para agrupar elementos hijos o texto, al cual se le puede dar algún tratamiento con los atributos comunes, como id, class, lang y title. El atributo id sirve para darle un identificador único en el documento a un elemento. El atributo class sirve para agrupar uno o más elementos con características comunes, es decir, crea una clase de elementos, de forma similar a las clases de programación orientada a objetos.

Por defecto el elemento div crea un bloque, de forma similar a los párrafos, títulos, tablas y otros elementos; que al ser colocados uno tras otros, son separados visualmente por "un cambio de línea". En algunas circunstancias, el autor necesita encerrar sólo unas letras o un trozo pequeño de texto dentro de un párrafo, dentro de un título, etc.; para darle un tratamiento especial. Este es el objetivo del elemento span, el cual carece de semántica al igual que div y es normalmente usado con los atributos class, id o lang.

Elementos de texto

En esta sección se presentarán los elementos más comunes para estructurar el texto del documento web: títulos de secciones, párrafos, texto preformateado, texto estructurado y listas de elementos.

Títulos de secciones

Los documentos en (X)HTML5 son divididos en partes con elementos como article y section. Por ejemplo, un libro se divide en capítulos y secciones. Tanto la obra como sus partes son identificadas con títulos (en inglés, headings). En el caso de libro, cada uno de sus capítulos, secciones, y el mismo libro, tienen un título que las identifica y distingue de las demás.

(X)HTML define 6 niveles de títulos en orden descendente de importancia h1, h2, ..., h6. El navegador u otro software podría usar los títulos del documento, por ejemplo, para construir una tabla de contenidos automáticamente. Es habitual que la primera actividad que realice un autor sea definir la estructura temática de su documento antes de empezar a escribir el contenido de cada sección.

El formato por defecto de cada título es dependiente del navegador. Es usual que empleen tamaños más grandes y mayor peso para que sean más vistosos. En general esto ocurre con todos los elementos visuales de (X)HTML y es bueno que el navegador escoja su formato por defecto. De esta forma, el autor se concentra en escribir el contenido del documento y el navegador escoge el formato ideal para un medio específico, por ejemplo, una limitada pantalla de un dispositivo móvil. Sin embargo, (X)HTML permite al autor controlar el formato utilizando hojas de estilo como se estudiará en el capítulo siguiente.

El xhtml_section_headings presenta un ejemplo de cómo se pueden usar los títulos de secciones dentro de los elementos article y section para estructurar las partes de una tesis en (X)HTML5. En este ejemplo, el título de nivel 1 (h1) se usa para el título de la tesis, los títulos de nivel 2 (h2) para los títulos de los capítulos, los títulos de nivel 3 (h3) para los títulos de las secciones, y así sucesivamente.




   
   Tesis: Representación de letras de canciones en XML



   

Tesis: Representación de letras de canciones en XML

Maicol Yaxon <myaxon@garach.edu>

Resumen

Dado que no existe un estándar para representar letras[...]

Objetivos

Objetivo general

El objetivo general de este trabajo es formular una espec[...]

Objetivos específicos

  1. Analizar estadísticamente los componentes típicos [...]
  2. Proponer una representación XML de los componentes[...]
  3. Generar tipos de documentos y esquemas de la repre[...]
  4. [...]
]]>
Secciones y títulos de un artículo en (X)HTML5. Correr este ejemplo.

En HTML 4.01 / XHTML 1.0 y versiones previas, no existen los elementos semánticos de estructura como article y section. Los autores recurrían a elementos genéricos de división del texto div o simplemente dejaban a los títulos flotar libremente entre el texto del documento, ya que el navegador asume que cada título está dentro de una sección implícita. Es decir, cuando se abre un título de igual o mayor nivel, el navegador asume que la sección anterior se debe cerrar. El uso de títulos fuera de artículos, secciones o elementos div, limita el poder de los estilos (CSS) o del comportamiento (JavaScript), y no se recomienda para documentos extensos o complejos.

5 pts.

Escriba el título de su sitio web en un título de nivel 1 (h1). No utilice elementos h1 para ningún otro título del documento. Su título del sitio debe estar en un elemento header.

Utilice un título de nivel 2 para el título de la página web (probablemente sea una répica del título del documento (X)HTML, el cual está en el elemento title). No utilice títulos de nivel 2 para otros títulos del documento.

Utilice títulos de nivel 3 (h3) para las secciones de contenido, que probablemente se repitan en su página web.

Párrafos

Un párrafo en (X)HTML se escribe con el elemento p como se aprecia en el listado xhtml_paragraphs_example. Aunque en HTML es opcional cerrarlo, es recomendable siempre hacerlo. A través de hojas de estilo se puede controlar el espaciado entre párrafos, la sangría y otros formatos. No escriba párrafos vacíos <p></p> para tratar de dejar espacio en blanco en el documento. La especificación (X)HTML recomienda al navegador ignorar estos elementos. Algunos autores, entonces, fuerzan el espaciado con párrafos que consisten de espacio no separable (<p>&nbsp;</p>), lo cual es el mal uso de la estructura (los párrafos) con fines de apariencia (el estilo).




   
   Programación en C++



Universidad de Costa Rica
Escuela de Ciencias de la Computación e Informática
CI1201 - Programación II

Programación en C++

Introducción a la programación

La computadora es un artefacto electro-matemático que puede ejecutar[...]

Hola mundo en C++

Desde el libro de Kernighan y Ritchie se ha seguido la tradición del primer programa a mostrar sea uno simple: escribir la cadena "Hola mundo" en la pantalla o algún otro medio. La forma de decir "Hola mundo en C++" se aprecia en el siguiente código:



           int main()
           {
            std::cout << "Hola mundo" << std::endl;
            return 0;
           }
         ]]>]]>

      
]]>
Párrafos y texto preformateado en (X)HTML. Correr este ejemplo.

A veces se quiere insertar un cambio de línea sin iniciar otro párrafo, por ejemplo, en un poema los versos se separan por cambios de línea y las estrofas por párrafos. Un cambio de línea se representa con el elemento vacío <br /> (acrónimo de break return). Algunos autores acostumbran dejar el espacio en blanco antes de la barra inclinada en las etiquetas vacías, ya que navegadores viejos que no implementan XHTML ignorarán la barra inclinada pensando que fue un "dedazo" del autor. Esta práctica ya no es necesaria.

Cuando la longitud de un párrafo excede el ancho de la ventana, el navegador inserta cambios de línea automáticos (word wrap). Cuando se quiere evitar que el navegador por esta característica separe dos palabras, estas deben separarse por un espacio no divisible (not breaking space) obtenible por la referencia de entidad &nbsp;. Por ejemplo, el código (506)&nbsp;905-LLAMEYA genera el texto "(506) 905-LLAMEYA". Si usted redimensiona la ventana del navegador, notará que el número de teléfono no será separado del código de país mientras se ajusta el párrafo automáticamente al tamaño de la ventana (probar en una ventana externa). La entidad &nbsp; está sólo disponible en HTML. En XHTML se puede usar su equivalente &#160;.

El hecho de que (X)HTML ignore los cambios de línea que usted escribe, no es práctico para escribir código fuente u otros tipos de escritos donde el espaciado en blanco es relevante. Para esas situaciones (X)HTML provee el elemento de texto preformateado pre, el cual instruye al navegador mantener los espacios en blanco, usar una fuente mono-espaciada y desactivar el ajuste automático de línea (word wrap). La especificación recomienda a los navegadores reemplazar tabuladores por 8 espacios en blanco, lo cual muchas veces resulta molesto, por eso, es recomendable utilizar espacios en blanco en lugar de tabuladores en las secciones pre o hacer modificaciones con programación del lado del servidor o JavaScript.

El navegador intentará interpretar el marcado (X)HTML que escriba dentro de un elemento pre, por esto debe al menos reemplazar los tres caracteres especiales (<, > y &) con sus referencias de entidad respectivas (&lt;, &gt; y &amp;), o escribir el texto dentro de una sección CDATA como se hizo en las líneas 26 a 34 del xhtml_paragraphs_example, lo cual tendrá efecto sólo si su documento es XHTML.

Un elemento hr (hard return) crea una línea horizontal que sirve para separar párrafos tratando de hacer una separación más visible entre ellos, por ejemplo, para separar los cambios temáticos entre estrofas de un poema. Es un elemento vacío y su apariencia debe ser estrictamente controlada con estilos.

5 pts.

Los elementos blockquote y q sirven para citar ideas de otro autor. Investigue en la especificación:

  1. ¿Cuál es la diferencia entre blockquote y q?
  2. ¿Debe el autor proveer comillas o estos elementos las agregan automáticamente?
  3. ¿Estos dos elementos permiten agregar varios párrafos p en su contenido?
  4. ¿En qué afecta indicar el idioma de la cita?
  5. ¿Cuáles de estos elementos se pueden anidar?
  6. ¿Qué abuso han históricamente cometido los autores de páginas web con el elemento blockquote
5 pts.

Su index.html debe hacer referencia a las grandes secciones de contenido de su sitio web (intro, xml, html, css, js, php). Escriba una sección "entrada de contenido" (y por tanto algo como <section class="content_entry"> para cada una de las secciones de su sitio web. Cada sección de contenido debe tener al menos un título, una imagen y un párrafo. El párrafo debe explicar al visitante de qué se trata esa sección.

Texto estructurado

(X)HTML define los elementos de frase (phrase elements) para agregar información a fragmentos de texto. Son elementos que afectan no a un párrafo sino sólo a algunas palabras de un párrafo, por ejemplo, denotan énfasis en una palabra, un trozo de código, una abreviatura, etc. La xhtml_phrase_elements lista los elementos de frase definidos en (X)HTML.

Elemento Descripción
abbr Indica una abreviatura, ej.: WWW, HTTP, etc., PhD. Son siglas o palabras reducidas.
acronym Indica un acrónimo, ej.: sonar, codec, JSON. Son abreviaturas que se leen como si fueran una palabra normal.
cite Indica una cita o referencia a otras fuentes. No soportado en la mayoría de navegadores.
code Indica un fragmento de código informático.
dfn Indica un término que se está definiendo.
em Indica énfasis.
kbd Indica que el texto debe ser ingresado o tecleado por el usuario.
samp Indica salida de programas informáticos.
strong Indica mayor énfasis.
var Indica una variable de un programa informático.
Elementos de frase en (X)HTML

Los dos elementos de frase de uso más común son em y strong. Normalmente los navegadores los despliegan en itálicas y negritas respectivamente, pero se puede alterar con hojas de estilo. Los demás elementos de frase están orientados a documentos técnicos. El listado xhtml_phrase_elements_example muestra el uso de algunos de estos elementos.


   Se dice que las entidades describen la estructura física
   y los elementos la estructura lógica de los documentos
   XML.
   La estructura lógica (elementos) y física (entidades) se representa dentro del
   documento 
   XML agregando el marcado, el cual
   se delimita de los datos de carácter encerrando la descripción de los
   elementos dentro de paréntesis angulares ("<" y ">"),
   que se conocen como etiquetas y las referencias a entidades entre
   el signo "&" y el punto y coma (";"). Es decir, el
   texto encerrado dentro de estos cuatro caracteres se conoce como marcado,
   lo restante como datos de carácter. La combinación del marcado
   más los datos de carácter son el texto XML [Gold99].

]]>
Elementos de frase en (X)HTML. Correr este ejemplo.

Todos los elementos de frase tienen un atributo title, en el cual se puede escribir información adicional que aparece cuando hay cierta interacción con el elemento, normalmente un "tooltip" cuando el puntero del ratón pasa sobre ellos. Esto es útil para expandir el significado de las abreviaturas y acrónimos sin tener que incluir estas definiciones explícitamente en el texto cada vez que se quiere usar la abreviatura. Nótese que esto se hizo en el listado xhtml_phrase_elements_example para la abreviatura "XML" que aparece dos veces (líneas 4 y 6), lo que genera redundancia de código. Teóricamente esta redundancia se puede evitar en XHTML definiendo entidades generales en el parámetro interno del tipo de documento, sin embargo, los navegadores actuales las ignoran, por lo que la mayoría de autores prefieren hacer algún tipo de programación del lado del servidor antes de despachar la página web.

Los elementos sub y sup sirven para declarar subíndices y superíndices respectivamente. Aunque tienen utilidad matemática y en otras notaciones científicas, realmente se mantienen en la recomendación para otros textos. Ejemplos:

Subíndices y superíndices en (X)HTML
Texto Código (X)HTML
El 1ro de la clase El 1<sup>ro</sup> de la clase
May 3rd, 2011 May 3<sup>rd</sup>, 2011
C6H12O6 C<sub>6</sub>H<sub>12</sub>O<sub>6</sub>

El elemento time aparecido en (X)HTML5 permite especificar que un trozo de texto representa una fecha, una hora o ambas; lo que posibilita a los programas su procesamiento, por ejemplo, para agregar un evento a la agenda del usuario, hacer conversiones de huso horario, guiar a los motores de búsqueda a indexar la fecha correcta, etc. El contenido del elemento time permite escribir la fecha en el formato que prefiera el autor, y el atributo datetime en formato "YYYY-MM-DDThh:mm:ss.sss±HH", el cual puede ser entendido por las computadoras. Ejemplos:

Estimado cliente. Su tiquete para el vuelo LA389 del

ha sido reservado con éxito. La hora actual de su destino, San Pedro Sula, es
 Recuerde registrar este evento en su agenda.

©2012 Tali Van Airlines Group. Documento generado el

]]>
Ejemplos de uso del elemento time

5 pts. Investigue los elementos del e ins en la especificación HTML 4.01, haga un ejemplo y describa cuál es su utilidad.

5 pts. Investigue los elementos i, b, s, small y mark en la especificación HTML5. ¿Cuál es la diferencia entre em e i? ¿Cuál es la diferencia entre strong y b? ¿Cuál es la diferencia entre del y s? Si un documento (X)HTML sólo debe representar contenido y no presentación ni comportamiento ¿por qué el estándar (X)HTML5 los mantiene?

Listas

(X)HTML permite definir listas de ítemes. Las hay en tres tipos: listas ordenadas, listas no ordenadas, y listas de definiciones. Las tres se pueden anidar. El xhtml_lists_example muestra un ejemplo de los tres tipos de listas y su anidamiento:


   

Puesto: Desarrollador web

Requisitos:

  • Conocimiento de estándares web
  • Programación en PHP o JSP
  • DBMS libres: PosgreSQL, MySQL o SQLite
  • Afiliado al colegio respectivo

Procedimiento de reclutación

  1. Llenar la fórmula RE-TI-C-2348 a mano
  2. Presentarla en las oficinas centrales
  3. Si es seleccionado:
    1. Presentarse a realizar el examen RE-TI-E-23
    2. Presentarse a realizar el examen RE-LG-E-02
    3. Si es seleccionado: presentarse a trabajar

Definiciones

DBMS
Database Management System
RE-TI-C-2348
Fórmula de cualidades para TI
RE-TI-E-23
Examen de tecnologías web
RE-LG-E-02
Examen básico de inglés
]]>
Listas de elementos en (X)HTML. Correr este ejemplo.

Las listas ordenadas se escriben con el elemento ol (ordered list). Sirven para indicar que los ítemes en la lista siguen cierto orden, como en una serie de pasos a ejecutar o cuando se quiere simplemente enumerar ítemes. Cada ítem de la lista se escribe dentro del elemento li (list item). Los navegadores les anteponen números arábigos por defecto, pero con estilos estos se pueden cambiar por números romanos, letras u otras formas. El atributo start del elemento ol en (X)HTML5 permite indicar el número con el cual se inicia el conteo, y si no se incluye se asume que es 1.

Las listas no ordenadas se escriben con el elemento ul (unordered list). Sirven para indicar una lista de ítemes que no siguen un orden inherente. Visualmente se anteceden con una viñeta circular que puede cambiarse con estilos a rectángulos u otras figuras.

Las listas de definiciones se escriben con el elemento dl (definition list). Sirven para escribir glosarios u otros tipos de estructuras similares. A diferencia de los tipos de listas anteriores, los ítemes de las listas de definiciones constan de parejas término-definición. El término se escribe con el elemento dt (definition term) y su definición con el término dd (definition description).

Imágenes

La característica más notable del hipertexto es el soporte de varios medios, entre los que se incluyen las imágenes, las cuales se almacenan en recursos (archivos) separados al documento web y se referencian desde éste. Para incluir una imagen se utiliza el elemento vacío img, cuyo atributo src debe tener el URL que identifica el archivo con la imagen, y puede ser absoluto o relativo al documento. La sintaxis más básica del elemento img es como sigue.

<img src="imagen.url" alt="descripción de la imagen" />

(X)HTML requiere un texto alternativo que será desplegado cuando la imagen no es cargada por alguna razón, como imagen inexistente o porque el usuario ha deshabilitado las imágenes en su navegador. Algunos navegadores muestran este texto como un "tooltip" cuando el puntero del ratón pasa sobre ellas, pero esa función es realmente responsabilidad del atributo title, el mismo que se usa en los elementos de frase estudiados en la sección de texto estructurado. Si la imagen se va a usar como una decoración y no se quieren "tooltips", asigne un valor vacío en estos atributos, de la forma <img alt="" title="" ... />. La apariencia del texto alternativo se puede ajustar con hojas de estilo.

Tamaños de imagen

Cuando el navegador está cargando un documento web y encuentra una etiqueta <img src="imagen.url" alt="algún texto" /> con esos atributos, solicita al servidor web que le envíe una copia de la imagen. Mientras ésta llega, el navegador sigue cargando (rendering) el resto del documento (X)HTML. Es muy probable que termine de mostrar el documento antes de que la imagen llegue y que el visitante empiece a leer el documento. Cuando finalmente la imagen es recibida, el navegador la insertará en el lugar donde encontró el elemento img correspondiente, desplazando el texto que se encuentre debajo. Esto es molesto para el lector, en especial si el documento tiene un considerable número de imágenes o son de gran tamaño o ambas.

El problema anterior se soluciona especificando las dimensiones de la imagen en el documento (X)HTML, de tal forma que el navegador pueda reservar espacio para la imagen antes de que esta sea recibida. Simplemente especifique las dimensiones en pixeles con los atributos width y hight.

<img src="imagen.url" alt="texto alternativo" width="320" height="280" />

Si el valor indicado en los atributos ancho o alto de img no coincide con el tamaño real de la imagen, el navegador la escalará. También se puede especificar en ellos un porcentaje de la ventana, algo como width="75%". Normalmente las aplicaciones de diseño web se encargan de asignar los valores reales de la imagen en forma automática. El ancho y alto de una o varias imágenes y otros detalles se pueden controlar con estilos, lo cual es muy útil para un conjunto grande de imágenes que comparten las mismas dimensiones.

Formatos de imágenes

Aunque existen muchos formatos de imágenes, sólo unos pocos se pueden utilizar en la web. La tab_formatos_imagen muestra una comparación de los formatos más soportados entre los navegadores actuales. Es tentador publicar imágenes de alta calidad, pero su tamaño será considerable y tardarán en cargarse en proporción inversa al ancho de banda del visitante. Si una o muchas imágenes hacen lento el cargado de una página web, es una invitación al lector para abandonarla. El autor debe hacer un balance entre la calidad de la imagen y su tamaño en bytes. Por esto es importante que conozca la diferencia entre los formatos disponibles y cómo ajustar este balance.

Formato Tipo Colores Transparencia Pérdida Utilidad
PNG Escalar 256 / 16M No Ilustraciones
JPEG Escalar 16M No Fotografías
GIF Escalar 256 No Animaciones sencillas
SVG Vectorial 16M No Ilustraciones
Formatos de imagen soportados por navegadores

Cuando un autor quiere representar alguna pieza de información en forma gráfica, debe decidir si utilizar una fotografía, una ilustración o una animación. Esta decisión ayuda en gran medida a delimitar el formato a escoger.

Una fotografía tiene millones de colores o grises. Se obtienen por cámaras digitales o escáneres. Ambos dispositivos no proveen información de transparencia. El formato más recomendable para fotografías es el JPEG, creado en 1992 por el Joint Photographic Experts Group. Es un algoritmo de pérdida de calidad que trata de descartar detalles que el ojo humano no percibe con el fin de ahorrar espacio. El formato PNG (Portable Network Graphics) también puede almacenar fotografías, pero sin pérdida de calidad, lo cual es poco recomendable para el web ya que su tamaño compromete la velocidad de carga del documento.

Una ilustración es una imagen, normalmente en dos dimensiones, que contiene texto o lo complementa. Suelen contener diagramas o dibujos hechos en un programa de cómputo, en contraposición a los obtenidos por una cámara o escáner. La cantidad de colores de una ilustración suele ser reducida. El formato PNG o SVG (Scalar Vector Graphics) son aptos para ilustraciones, la diferencia entre ambos es el tipo de imagen: escalar o vectorial respectivamente.

Una imagen escalar es un mapa de bits, es decir, una matriz de tamaño definido donde cada celda o pixel almacena un color codificado en forma numérica. "Redimensionar" a menor tamaño una imagen escalar provoca que ésta se deforme en especial si no se mantiene su proporción. Si se agranda una imagen escalar provocará que los pixeles se propaguen a las celdas adyacentes, generando zonas de colores poco agradables a la vista humana.

Una imagen vectorial está compuesta por figuras geométricas como puntos, líneas, curvas o polígonos. Sus atributos como posición y tamaño son los que se almacenan en el archivo. "Redimensionar" una imagen vectorial a cualquier tamaño significa reajustar las posiciones de las figuras geométricas y volverlas a pintar, lo que provoca que la imagen siempre se vea agradable a la vista humana.

La explicación anterior facilita la decisión hacia SVG como formato de elección para ilustraciones, sin embargo hay que tener en cuenta que, aunque SVG es un estándar abrigado por el W3C, su implementación en los navegadores actuales es parcial y quizá ausente en aquellos de dispositivos móviles, debido a que su despliegue requiere de mayor poder de cómputo que los otros formatos. Algunos sitios web como Wikipedia usan SVG, pero si el navegador no soporta este formato, el servidor web envía a cambio un PNG autogenerado.

Si el autor encuentra que una animación es el mejor medio de comunicar algo, puede usar una imagen GIF (Graphics Interchange Format), que permite animaciones escalares muy sencillas y limitadas a 256 colores. Si se requiere animaciones vectoriales, el autor podría programar un elemento canvas con JavaScript, o tecnologías propietarias como Adobe Flash. Si se requiere animaciones de más de 256 colores, se trata de un video y estos pueden incrustarse con objetos como se estudiará en la sección Objetos multimedia.

Indiferentemente de si se utilizan imágenes escalares o vectoriales, el autor debe conseguir reducir el tamaño tanto como se pueda sin que la imagen se vea desagradable al lector. El autor necesita que el editor de imágenes lo apoye en esta labor. Normalmente estos programas proveen una opción que permite variar el tamaño en bytes de la imagen u otros parámetros y ver el efecto en tiempo real en la visualización de la misma. Es importante que el autor guarde además la imagen original en un formato con mayor calidad o sin pérdida alguna.

Existe considerable cantidad de editores de imágenes disponibles, desde los renombrados paquetes de Adobe: Photoshop para imágenes escalares e Illustrator para imágenes vectoriales. Como opciones libres a estos programas se puede citar Gimp e Inkscape respectivamente.

5 pts. Suponga que está escribiendo un manual de usuario en (X)HTML ¿Qué formato de imagen utilizaría para una captura de pantalla (screenshot) del programa en cuestión? Justifique la respuesta.

Figuras

Cuando se inserta una imagen, vídeo, un listado de código u otro objeto en un documento, es muy común agregar algún texto que dé una explicación corta, los derechos de copia u otros detalles del objeto. Este texto, a veces conocido como leyenda, rótulo o título del objeto (caption), forma junto con el objeto una unidad; es decir, deben estar juntos en el documento. Por ejemplo, si la imagen se mueve de lugar en el documento, el rótulo debe viajar con ella, de lo contario pierde su sentido. (X)HTML5 provee el elemento figure para unir una imagen o cualquier objeto con su leyenda, la cual se indica con el elemento figcaption como se muestra en el xhtml_figure_example.


   
   
Una imagen escalar incrementada 4x
]]>
Agrupar una imagen con una leyenda en (X)HTML5. Correr ejemplo completo.

En caso de proveerse una leyenda con el elemento figcaption, se convierte en opcional el proveer un texto alternativo con el atributo alt de img, como ocurrió en la línea 2 del xhtml_figure_example. Es importante reiterar que el elemento figure no está limitado sólo a imágenes, si no a cualquier objeto o trozo de texto que necesite una leyenda.

Icono de favoritos

Se ha convertido en una práctica común proveer un pequeño icono que ayuda al visitante a identificar la página web. A este icono se le suele llamar icono de favoritos ó simplemente favicon (contracción de favorites icon), porque el navegador lo almacena junto a los favoritos, y lo despliega en la barra de direcciones o en las pestañas. Usualmente el mismo icono se utiliza en todas las páginas de un sitio web, lo que le da identidad al sitio entero y por ende también se le llama icono de sitio web (web site icon).

El favicon es un archivo PNG, o uno con extensión .ico que puede contener imágenes de varios tamaños. Normalmente son de 16x16 pixeles y utilizan fondo transparente. El documento web debe indicar el favicon en su encabezado (head) utilizando el elemento vacío link, el tipo de imagen y su URL, como se muestra en xhtml_favicon_inclusion. A modo de conveniencia véase Wikipedia para otros tipos de imágenes, enlaces y restricciones a la hora de declarar favicons.


   ...
   

]]>
Método más común de incluir un icono dentro de una página web.

Tablas

(X)HTML permite organizar datos en forma tabular con el elemento table. Una tabla es una secuencia de filas declaradas con el elemento tr (table record); y cada fila se compone de celdas td (table data). El xhtml_simple_table muestra una tabla sencilla compuesta de cuatro filas y tres columnas.


    (1,1) (1,2) (1,3) 
    (2,1) (2,2) (2,3) 
    (3,1) (3,2) (3,3) 
    (4,1) (4,2) (4,3) 

]]>
Una tabla sencilla en (X)HTML compuesta de 4 filas y 3 columnas

Como se dijo antes, una tabla es una secuencia de filas, y las filas se pueden clasificar en tres tipos: filas que forman el encabezado de la tabla, filas que forman el cuerpo de la tabla y filas que forman el pie de tabla. Es importante poder indicarle al navegador cuáles filas conforman cada parte de tabla, de esta forma, el navegador podrá resaltar las filas especiales, repetir el encabezado cuando al imprimir el documento la tabla se extiende por varias páginas y funcionalidades similares. El estándar (X)HTML provee los elementos: thead (acrónimo de table head) para distinguir las filas que conforman el encabezado de la tabla; tbody para aquellas que conforman el cuerpo de la tabla; y tfoot para las que conforman el pie de la tabla, tal como se hizo en el xhtml_table_tiobe.


   Lenguajes de programación más populares según TIOBE
   
       #  Lenguaje     Popularidad 
   
   
       1  Java         17.11% 
       2  C            17.09% 
       3  C#            8.24% 
       4  C++           8.05% 
       5  Objective-C   7.74% 
       6  PHP           5.56% 
       7  Visual Basic  4.37% 
       8  JavaScript    3.39% 
       9  Python        3.29% 
       10 Perl          2.70% 
   
   
       Total         77.54% 
   

]]>
Encabezado, cuerpo y pie de tabla en (X)HTML. Correr ejemplo completo.

(X)HTML permite al autor diferenciar las celdas de encabezado con el elemento th (table head) de las celdas de datos td (table data). Nótese que las celdas de encabezado pueden estar tanto en las columnas como en las filas. Esta diferenciación permite al navegador dar mayor énfasis a los encabezados. El autor puede proveer un valor abreviado en el atributo abbr de una celda encabezado th; en caso de que el navegador no tenga suficiente espacio para desplegar la tabla, utilizará la abreviatura indicada.

Es válido tener en una tabla celdas sin contenido. También una celda (de datos o encabezado) puede ocupar dos o más columnas, dos o más filas, o ambas. La cantidad de columnas que ocupa una celda se indica con el atributo colspan y la cantidad de filas que ocupa una celda se indica con el atributo rowspan. El valor por defecto para ambos atributos es 1. En la línea 19 del xhtml_table_tiobe se indica que la celda con el valor "Total" ocupa dos columnas: la columna # y la columna Lenguaje.

Es conveniente que el autor provea una leyenda explicando al lector el objetivo de la tabla, con el elemento caption como se hizo en la línea 2 del xhtml_table_tiobe. Con estilos se puede controlar si la leyenda debe aparecer arriba o debajo de la tabla. Una forma alternativa en (X)HTML5 es introducir tanto la tabla como su leyenda en un elemento figure como se explica en la sección Figuras.

Por defecto el navegador no dibuja bordes en las celdas ni en la tabla. Esto puede ser confuso para el autor, pero es una responsabilidad de las hojas de estilo (CSS) y no de (X)HTML, lo cual se estudiará en el próximo capítulo. Si se requiere de bordes, el autor puede rápidamente agregar en el encabezado de su documento (X)HTML las reglas de estilo de las líneas 7 y 8 del xhtml_table_border_css.




   
   ...
   


...


]]>
Dos reglas de estilo CSS para agregar bordes en las tablas de un documento web.

Objetos multimedia

El elemento img sirve para incrustar una imagen externa en un documento web. Pero cuando se quiere insertar un recurso de otra naturaleza, como un sonido, un video, otra página web, un applet de Java, u otro tipo de recurso, se debe emplear el elemento object. Según el estándar, un object es un elemento que puede representar un recurso externo como una imagen, contexto anidado de navegación, o un recurso que debe ser procesado por una extensión del navegador (plugin).

El uso del elemento object ha caído significativamente debido a que (X)HTML5 define nuevos elementos para representar contenido multimedia, principalmente: video, audio, y canvas. En cuanto a los applets de Java son desalentados en favor de JavaScript. Y la posibilidad de incrustar un documento web dentro de otro nunca ha sido implementado de una forma natural por los navegadores, en especial es difícil de presentar con estilos CSS; lo mismo ocurre con el elemento iframe. De esta forma, la utilidad del elemento object queda casi limitada a incrustar contenido manipulado por extensiones (plugins), en especial contenido para Adobe Flash.

[Contenido pendiente]

Hojas de estilo en cascada CSS

Un documento (X)HTML sólo debe tener contenido, es decir, los datos que el autor quiere publicar y su estructura. La apariencia o presentación de un documento web debe especificarse en un archivo externo llamado hoja de estilos que indica cómo debe formatearse la información en la pantalla, en papel u otro medio de salida.

La separación del contenido y la presentación tiene grandes ventajas. Una hoja de estilos puede reutilizarse en todas las páginas de su sitio web, lo que les da uniformidad, facilita el mantenimiento y ahorra ancho de banda. Una misma o varias páginas web pueden ajustarse a diferentes necesidades simplemente cambiando la hoja de estilos. Así el autor puede tener un juego de hojas de estilo en su sitio web; una para cada necesidad: un diseño avanzado para el navegador, grandes contrastes para personas con necesidades especiales, estilos amigables para impresión en papel (printer friendly), etc. De esta forma, una misma página web puede verse en formas distintas sin cambiar la información que contiene.

Generalidades de las hojas de estilo

Una hoja de estilos es un archivo de texto que contiene reglas de formateo de elementos utilizando un lenguaje especial conocido como hojas de estilo en cascada (CSS, Cascading Style Sheets), el cual es estándar y definido por el W3C. Por ejemplo, la siguiente regla hace que todos los títulos de un documento web sean de color verde:

h1, h2, h3, h4, h5, h6 { color: green; }

En general una regla CSS tiene la siguiente sintaxis:

selector { declaration }

El selector determina cuáles elementos serán afectados por los estilos definidos en la declaración, y puede ser uno o varios elementos separados por comas. La declaración es una lista de parejas propiedad: valor que serán aplicadas a los elementos listados en el selector. Dichas parejas se separan por el símbolo punto y coma (;). Es opcional terminar en punto y coma la última pareja. Con esto la sintaxis se expande a:

element1, element2, ..., elementN
{
   property1: value1;
   property2: value2;
   ...
   propertyN: valueN;
}

Es muy conveniente que escriba comentarios explicando la intención de cada regla, o al menos de aquellas no triviales. Los comentarios utilizan la misma notación del lenguaje de programación C:

/* Las definiciones deben estar en negritas y no en itálicas como ocurre en ciertos
navegadores. Globalmente se usa verde para definiciones y títulos; azul para enlaces. */
dfn
{
   font-weight: bold;
   font-style: normal;
   color: #004444;
}

Ubicación de las reglas de estilo

La recomendación (X)HTML permite declarar reglas de estilo en cinco lugares:

  1. En el elemento mismo, con el atributo style.
  2. En el encabezado del documento web, con el elemento style.
  3. En un archivo .css externo el cual se liga al documento con el elemento link.
  4. En una hoja de estilos externa provista por el visitante (no por el autor).
  5. En la implementación del navegador web.

De los cinco lugares para especificar estilos en la lista anterior, el Consorcio Web (W3C) desalienta el uso los dos primeros, ya que el documento web debe almacenar contenido únicamente, no estilos; y los dos últimos están fuera del control del autor. Por eso, se aconseja al autor declarar las reglas de estilo siempre en una o varias hojas de estilos .css externas al documento web.

El listado css_locations muestra cómo declarar estilos en los tres lugares donde puede el autor. Supóngase que la línea 17 representa un archivo de texto con extensión .css que contiene sólo una regla y se adjunta al documento web con el elemento link en el encabezado del mismo (línea 4). Si dos o más hojas de estilo se incluyen en el encabezado, se procesarán en el mismo orden en que se incluyeron.



   
      
      
      
      ...
   
   
      

Lorem ipsum ad his scripta blandit partiendo...

p { color: green } ]]>
Lugares donde se pueden especificar reglas de estilo CSS

El atributo media del elemento link indica si las reglas de estilo aplican a un medio específico, como la pantalla (screen), la impresora (print), programas de lectura sintetizada (aural), computadoras de mano (handheld), televisores (tv) y otros. En el ejemplo anterior, un navegador cargará la hoja styles1.css (línea 4) y los aplicará al documento web para ser visualizado en la pantalla. Si el usuario decide imprimir el documento, el navegador cargará styles2.css (línea 5) y los aplicará en la copia que enviará a la impresora. El atributo media es opcional, y si no se especifica en un elemento link, se asume que esa hoja de estilos aplicará a todos los medios, lo que equivale a darle el valor media="all". El atributo media puede contener varios valores separados por comas, de esta forma, una hoja de estilos puede aplicarse a varios medios simultáneamente.

El segundo lugar donde se pueden escribir reglas de estilo es en uno o varios elementos style dentro del encabezado (head) del documento (X)HTML, como se aprecia en las líneas 6 a 8 del listado css_locations. Nótese que el encabezado head admite combinar hojas de estilo externas y elementos style en cualquier orden. La especificación CSS indica que el navegador debe respetar este orden, de tal forma que las reglas de estilo que se encuentran en un archivo .css, tienen el mismo efecto que si se escribiesen directamente en un elemento style del encabezado.

El tercer lugar donde se puede especificar reglas de estilo es en el atributo style del elemento mismo, como se hizo en la línea 12 del listado css_locations. En este caso, todas las propiedades aplicarán únicamente a dicho elemento por lo que no es necesario especificar un selector, ni agrupar las propiedades dentro de llaves { }.

El principio de cascada

En vista de que hay cinco lugares opcionales donde se especifican estilos, puede ocurrir que para una propiedad no haya ninguna regla, o bien hayan varias. El navegador necesita un algoritmo que especifique cómo actuar en estos casos, al cual se le llama el principio de cascada y consta de otros tres principios.

Si dos o más reglas compiten para darle estilo a una misma propiedad, recibirá mayor prioridad aquella que tenga mayor especificidad en su selector. A esto se le llama principio de especificidad.

Si dos reglas compitiendo por la misma propiedad tienen igual especificidad, se tomará la que aparezca de último, es decir, tendrá más peso aquella que se encuentre más cerca del elemento. A esto se le llama el principio de ubicación.

Cuando por el contrario, no se especifican reglas para una propiedad, el navegador debe seguir un principio más, el principio de herencia, el cual indica que ante la ausencia de una regla de estilo, el navegador debe aplicar el estilo del elemento padre. No todos las propiedades son heredables por defecto. Por ejemplo, la fuente lo es pero no el margen. De esta forma, al asignar la fuente al elemento body, todos los párrafos la heredan, lo cual es deseable; pero si se asigna un margen grande al body para mantener una separación visual con los bordes de la ventana del navegador, sería indeseable si este borde se aplicara entre párrafo y párrafo.

El uso de los tres principios: ubicación, especificidad y herencia para determinar cuál regla debe aplicar a una propiedad de estilo de un elemento se conoce como principio de cascada. Los navegadores implementan este principio dándole puntos o pesos a cada regla de estilo siguiendo un cálculo propuesto en la especificación CSS, que cualitativamente se puede resumir en lo siguiente:

Ante la ausencia de una regla, el estilo se hereda del elemento padre si la propiedad es heredable, si no, se usa el estilo por defecto del navegador. Si dos o más reglas compiten por darle estilo a una misma propiedad, se tomará aquella con mayor especificidad de su selector, independientemente de dónde esté ubicada. Con dos reglas de igual especificidad, ganará la que aparezca de último.

A modo de ejemplo, el listado css_location_doc muestra un documento web que tiene dos párrafos y estilos definidos en tres lugares: una hoja de estilos externa (cascading1.css) enlazada en la línea 4; un elemento style en el encabezado (líneas 5 a 7), y un atributo style en el segundo párrafo (línea 18). Se estudiará el efecto de estos estilos en tres propiedades: el color, la fuente y el margen.



   Estilos en conflicto: cascada
   
   



   

Este es el primer párrafo. Ninguna regla de estilo para p especifica la fuente, por lo que hereda la fuente de su elemento padre body. Aunque hay una hoja de estilos externa que especifica que el color del texto de los párrafos debe ser rojo, éste es verde azulado porque hay una regla en el encabezado del documento, que está más cerca de este párrafo.

Este es el segundo párrafo. Tiene un atributo de estilo que sobrescribe el color del texto a verde, ya que por especificidad está más cerca del elemento. Ninguna regla de estilo formatea la separación vertical entre párrafos, por lo que se aplica la que el navegador tenga implementada internamente.

]]>
Ejemplo de estilos en cascada. Correr este ejemplo.
body
{
   font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
   margin: 2.5cm;
}

p { color: red; }
Archivo cascading1.css referenciado en el ejemplo anterior.

La fuente es una propiedad heredable de acuerdo a la especificación CSS. La mayoría de navegadores asumen una fuente con serifas, como Times New Roman. Al cargar la hoja de estilos el navegador procesa la regla que indica que la fuente del cuerpo (body) del documento debe mostrarse en Verdana, que es por el contrario una fuente sin serifas (sans-serif); cualquier regla del autor tiene más prioridad que el valor por defecto del navegador y por ende el navegador debe usar Verdana para formatear el texto del body, el cual es vacío (body no tiene texto directamente, sino dos elementos p hijos).

Al desplegar el primer párrafo (línea 11), el navegador no encuentra una regla de fuente para dicho elemento de párrafo. Como es una propiedad heredable, el navegador toma la fuente del padre del párrafo que es el elemento body, y por ende despliega el texto del párrafo en Verdana. Esto mismo ocurre recursivamente para los elementos hijos del párrafo, como em, strong y code; y luego para el párrafo siguiente. De esta forma, todo el documento aparece en Verdana como el autor podría esperar.

La propiedad de margen (margin) no es heredable de acuerdo a la especificación CSS. El navegador web asume un margen nulo o minúsculo para el body, por lo que el texto se suele pegar con los extremos de la ventana del navegador. Al encontrar la regla margin: 2.5cm, el navegador la aplica al elemento body, haciendo que el margen del documento sea de 2.5 centímetros. Sin embargo, al no ser una propiedad heredable, el navegador no aplica un margen de 2.5 centímetros a los párrafos ni a los elementos em, strong y code, sino que asume el margen por defecto, que es de unos cuantos pixeles para párrafos y de 0 pixeles para los otros elementos citados.

El color es una propiedad heredable según la especificación CSS. El navegador no encuentra una regla para el color de body y asume el por defecto del navegador, que es negro. La regla p { color: red; } en la hoja de estilos cascading1.css, indica al navegador que pinte todos los párrafos en rojo. Pero en la línea 6 del documento web del listado css_location_doc compite por la misma propiedad: establecer el color de los párrafos en verde azulado (teal). Estas dos reglas están en conflicto, y ganará la que tenga mayor especificidad en el selector, sin embargo ambas tienen el mismo selector; y en tal caso el navegador deberá aplicar la que aparezca de último de acuerdo al principio de ubicación, y por ende, los parrafos aparecerán en verde azulado.

Al pintar el segundo párrafo que inicia en la línea 18 del listado css_location_doc, el navegador encuentra una regla para la propiedad color en su atributo style. De acuerdo al principio de especificidad esta regla tiene la mayor prioridad y por ende, el segundo párrafo aparecerá en verde simple en lugar de verde azulado.

El operador @

Selectores

Valores de propiedades

Los valores que pueden tomar las propiedades son de muy diversa naturaleza. Sin embargo, existen algunos dominios comunes que se resumen en la css_value_types y a los cuales se les hará referencia luego en este documento.

Dominio Descripción Ejemplos
inherit Se le da el valor inherit a una propiedad cuando explícitamente se quiere especificar que esa propiedad tome el mismo valor que la del elemento padre.
p { margin: inherit; }
<length>

Son magnitudes compuestas siempre de un valor y una unidad, como 2.5cm las cuales no deben estar separadas por espacios. La unidad se puede omitir sólo cuando la magnitud es 0. Hay dos tipos de unidades:

  • Absolutas: centímetros (cm), milímetros (mm), pulgadas (in), puntos (pt) y picas (pc).
  • Relativas: tamaño de fuente (em), tamaño de la letra "x" en la fuente actual (ex), pixeles (px), y porcentajes del valor de la propiedad del elemento padre (%).
body { margin: 2.5cm; }

h1
{
   margin-top: 2em;
   margin-bottom: 0;
}

pre { font-size: 85%; }
<number> Son números sin unidades.
div.content { z-index: 2; }
<url> URL hacia otro recurso, como una imagen, sonido, etc. Si el URL es relativo, lo será con respecto a la hoja de estilos y no al documento (X)HTML. Encerrar el URL entre comillas es opcional. No debe separarse la palabra url del paréntesis que abre.
body
{
   background: url(water.png) repeat;
}
<color>

Hay tres formas de especificar colores en CSS:

  • Nombres predefinidos. Hay 17 colores predefinidos como se explica más adelante. Los nombres no son sensitivos a mayúsculas y no se deben especificar dentro de comillas.
  • Notación rgb(). Permite construir un color con la cantidad de rojo, verde y azul, sea con valores entre 0 y 255 (o su correspondiente hexadecimal), o porcentajes. No se debe separar la palabra rgb de los paréntesis que abren.
  • Notación #. Se especifica las cantidades de rojo, verde y azul en notación hexadecimal antecedidos por un símbolo de número, de la forma #rrggbb, o #rgb si los dígitos de cada componente se repiten. Las letras hexadecimales pueden estar en mayúsculas o minúsculas o ambas.
body { background: black; }
h1 { color: rgb(245, 255, 250); }
h2 { color: rgb(100%, 75%, 50%); }
pre
{
   border: solid 1px;
   border-color: #80c0a0 #000 #000 #80c0a0;
   background: #EFE;
}
Dominios comunes de ciertas propiedades CSS
black navy blue teal green olive maroon purple fuchsia red orange yellow lime aqua gray silver white

Propiedades

El modelo de fuente

El modelo de color

El modelo de caja

El modelo de visualización

Comportamiento con JavaScript

JavaScript es un lenguaje interpretado por el navegador web que permite al autor manipular dinámicamente el documento, sus estilos y la ventana misma del navegador, para hacer la experiencia del lector más natural y amena. JavaScript fue creado en 1995 por Brendan Eich cuando trabajaba para Netscape. Un año después Microsoft produjo su propia versión llamada JScript. También en 1996, Netscape sometió JavaScript a la asociación Ecma International para consideración como estándar de la industria, el resultado fue ECMAScript.

ECMAScript es un estándar internacional de un lenguaje genérico de "scripting" para extender la funcionalidad de un programa cualquiera, no sólo navegadores web. Hay un número creciente de implementaciones basadas en ECMAScript que además extienden su funcionalidad, como el inicial JavaScript de Netscape, JScript de Microsoft, ActionScript de Macromedia (adquirida por Adobe), SpiderMonkey y Rhino de Mozilla, etc. Sin embargo, el nombre ECMAScript no tomó popularidad, y cuando la mayoría de la gente dice "JavaScript" está haciendo referencia al lenguaje en forma general, no a la implementación de Netscape, y así se hará en este documento.

Cualquier software que quiera permitir al usuario automatizar tareas propias, en lugar de crear un nuevo lenguaje de scripting, puede echar mano de JavaScript. De esta forma, JavaScript es por naturaleza un lenguaje genérico. Un desarrollador que conozca este lenguaje, puede aprovechar su conocimiento para automatizar variedad de aplicaciones; como ocurre en la actualidad en programación de dispositivos móviles, acceso a bases de datos orientadas a documentos, animación digital y otros. Pero su uso más difundido ha sido históricamente la web, en la programación en el lado del cliente y más recientemente en el servidor web. En este material se presentará este lenguaje precísamente ligado al navegador web.

Generalidades

JavaScript es un lenguaje similar a C/C++/Java. Es sensitivo a mayúsculas y minúsculas, por lo que resulta más consistente con XHTML que con HTML. Aunque no es obligatorio, cada sentencia en JavaScript debe terminar en punto y coma, y se considera una mala práctica omitirlos. Los comentarios utilizan la notación de C++:

// comentario hasta el final de línea
/* comentario que puede
   extenderse varias líneas */

El código JavaScript puede aparecer en cuatro lugares relacionados con el documento web: en el elemento script, en un archivo .js externo, en un evento intrínseco, y con el pseudoprotocolo javascript:.

Código JavaScript en el elemento script

Se puede escribir código JavaScript en el contenido del elemento script, el cual debe ser hijo directo de head o body. El siguiente ejemplo muestra los cuadrados de los primeros 20 números naturales:


   

Cuadrados naturales

]]>
Un elemento script en el cuerpo del documento. Correr este ejemplo

Mientras el navegador está cargando un documento web, va mostrando sus elementos (títulos, párrafos, imágenes, tablas, etc.), a medida que los encuentra. Lo mismo pasa con los scripts. Inmediatamente que el navegador encuentra un elemento script, ejecuta su código.

En el ejemplo del js_square_list_1, se invoca al método write() del objeto document que representa al documento ante JavaScript. El método document.write() recibe una lista de valores separados por coma y su salida es insertada como código HTML inmediatamente después del elemento script que lo invoca, es decir, su invocación altera la estructura del documento. Una vez que el script ha terminado su ejecución, el navegador continúa procesando el resto del documento como de costumbre, y procesará tanto el código provisto por el autor en el documento original como el código insertado con document.write() tras ejecutar el script.

Existen diferencias si el código JavaScript está en un documento HTML o XHTML. En XHTML el objeto document no dispone de un método write(), ya que XML prohíbe modificar el documento mientras éste se esté cargando [W3C]. Incluso en HTML, el uso de document.write() se considera ahora una pobre práctica de programación, sin embargo se utilizará en la primera parte de este capítulo por ser fácil de comprender. Si se incrusta código JavaScript en un documento XHTML que tiene caracteres especiales como menor que (<), mayor que (>), o ampersand (&), se debe encerrar en una sección CDATA:


]]>

Como se puede deducir del js_square_list_1, JavaScript interpreta el texto entre apóstrofes ('') y entre comillas ("") como cadenas de caracteres. Las variables no se declaran precedidas por su tipo de datos, sino por la palabra reservada var. Y el ciclo for tiene la misma sintaxis de C.

5 pts.

En un documento HTML5, modifique el ejemplo del js_square_list_1 para desplegar en una tabla HTML, las tablas de multiplicar del 1 al 20. La tabla debe tener una fila de encabezado, una columna de encabezado y 20x20 = 400 celdas de datos, como se ilustra a continuación. Asegúrese de que su documento sea válido ante los estándares.

*123...20
1123...40
2246...60
3369...80
..................
20406080...400
5 pts.

En un documento HTML5 escriba una tabla con las primeras 10 potencias naturales de los números 1 a 20. La tabla tendrá una fila de encabezado, una columna de encabezado y 20x10 celdas de datos. Indague sobre el método Math.pow(). Recuerde validar su documento. [Opcional: si gusta puede agregar su tabla de potencias al documento del ejercicio anterior].

El elemento script tiene cinco atributos opcionales: type, src, charset, defer y async. El atributo type indica el lenguaje de programación utilizado por el script. Hasta la fecha sólo existe un lenguaje reconocido: JavaScript, y es el considerado por defecto en HTML5, por lo que el programador puede omitirlo, como se hará en el resto de este capítulo. Los demás atributos se estudiarán en la próxima sección.

Código JavaScript en un archivo externo

El elemento script permite escribir código JavaScript en su contenido, pero el Consorcio Web recomienda sacar el comportamiento del documento web a un recurso reutilizable, por convención, un archivo con extensión .js. Este es el segundo lugar donde se puede escribir código JavaScript. El mismo elemento script permite hacer la inclusión del archivo externo con el atributo src. El ejemplo del js_square_list_2_xhtml tiene el mismo efecto que el ejemplo del js_square_list_1. Es importante resaltar que un script debe tener contenido o un recurso externo en el atributo src, pero no ambos, de lo contrario generará un documento inválido en (X)HTML5.


   

Cuadrados naturales 2

]]>
El código JavaScript puede estar en un recurso externo y ser importado con el atributo src del elemento script. Correr este ejemplo.
\n');
for ( var n = 1; n <= 20; ++n )
   document.write('
  • ', n, '2 = ', n * n, '
  • \n'); document.write('\n'); ]]>
    El archivo JavaScript squares_list2.js referido en el ejemplo anterior.
    5 pts.

    En los ejercicios sobre las tablas de multiplicar y las tablas de potencias, extraiga el código JavaScript que escribió a uno o varios archivos .js externos. Asocie el archivo .js en su documento (X)HTML. Asegúrese de que ambas tablas sean desplegadas correctamente en un lugar adecuado del documento.

    En HTML la etiqueta de cierre </script> es siempre requerida, aunque el contenido del script sea vacío; es decir, siempre se deben escribir de la forma <script src="archivo.js"></script>. En XHTML se puede tener una etiqueta vacía de la forma <script src="archivo.js"/>.

    Cuando el código de un script se encuentra en un archivo externo, el atributo charset permite indicar la codificación empleada del archivo .js si ésta difiere de la codificación del documento (X)HTML. Los atributos defer y asinc permiten controlar en qué momento se debe ejecutar el script, como se indica en la js_script_defer_async.

    defer async Comportamiento Ejemplo
    Si se omiten ambos atributos, el script es ejecutado inmediatamente; y antes de continuar procesando (parsing) el resto del documento. Dado que el código JavaScript está en un recurso externo, el navegador debe esperar a que éste se haya descargado completamente antes de continuar desplegando el documento.
    ]]>
    defer El script es ejecutado inmediatamente después de que el documento y sus requisitos (imágenes, hojas de estilo, etc.) se hayan terminado de cargar por completo. Este es el momento idóneo para ejecutar código JavaScript en la mayoría de casos.
    ]]>
    async Indica al navegador continuar cargando el documento y solicitar al servidor web el archivo .js, y cuando lo reciba, ejecutarlo simultáneamente con el cargado del documento. Sólo está disponible en HTML5 y no es soportado por Internet Explorer.
    ]]>
    defer async Carece de sentido. El navegador actuará como si sólo se hubiese especificado async.
    Los atributos defer y async permiten controlar el momento en que el navegador ejecuta el script.

    Los atributos defer y async se pueden especificar únicamente cuando el script externo no haga uso de document.write(); ya que una invocación a este método obliga al navegador detener el cargado del documento, esperar a que el script termine de generar contenido, analizarlo (parse) y luego continuar con el resto del documento.

    Código JavaScript en los eventos intrínsecos

    El tercer lugar donde se puede especificar código JavaScript es en los eventos intrínsecos de ciertos elementos, tales como onload, onmouseover y onclick, como se ilustra en el js_intrinsic_events_ex1. Este código JavaScript es ejecutado únicamente si el evento es accionado. Los eventos intrínsecos se estudiarán más adelante en este capítulo.

    
       

    Eventos en JavaScript

    ]]>
    El autor puede proveer código JavaScript se que ejecuta cuando un evento ha ocurrido, como presionar un botón en este caso. Correr este ejemplo.

    Código JavaScript en el pseudoprotocolo javascript:

    El cuarto lugar donde se puede ejecutar código JavaScript es en la barra de direcciones del navegador, en el destino de un enlace o cualquier otro lugar donde se pueda escribir un URL; con el pseudoprotocolo javascript:, que es seguido por una o varias instrucciones JavaScript separadas por punto y coma. El resultado de estas instrucciones, si lo hay, se toma como un string, y es desplegado en la ventana del navegador. Ejemplos:

    javascript:5%2
    javascript:x = 3; (x < 5) ? 'x is less' : 'x is greater'
    javascript:d = new Date(); typeof d
    javascript:for(i=0,j=1,k=0,fib=1; i>5; i++,fib=j+k,k=j,j=fib) alert(fib);
    javascript:s=''; for(i in navigator) s+=i+':'+navigator[i]+'\n'; alert(s);
    

    El pseudoprotocolo javscript: ha caído en desuso, y algunos navegadores como Chrome y Safari los ejecutan pero no reemplazan el documento actual por el resultado de la expresión, lo que produce la sensación de ser ignorados.

    Tipos de datos y variables

    JavaScript define siete tipos de datos: booleanos, números, cadenas de caracteres (strings), funciones, objetos, arreglos, y valores especiales. En las siguientes secciones se explorará cada uno de ellos.

    Números

    JavaScript no hace diferencia entre números enteros y de punto flotante. Todos son representados internamente como punto flotante de 64bits (IEEE 754). Las constantes literales numéricas de JavaScript siguen las mismas convenciones de C, excepto los números octales que no son parte de ECMAScript. La js_numeric_literals muestra algunos ejemplos de constantes literales numéricas.

    Tipo de constante literal Ejemplos
    Enteros en base 10 0, 16777216, -3
    Enteros hexadecimales 0xFEE0, -0xff
    Notación fija -3.141592, .1
    Notación exponencial 6.67e-11, .1E3
    Constantes literales numéricas en JavaScript

    Cuando un valor flotante llega a ser más grande que el más grande de los representables, se almacena con el valor especial Infinity o su opuesto negativo. Cuando se hace una operación indefinida, se genera un número especial NaN (not-a-number), el cual nunca es igual a nada, incluso ni a él mismo, por eso debe usarse la función especial isNaN(). Otra función práctica es isFinite(), que prueba si un número no es Infinite y no es NaN. A continuación una lista de constantes numéricas especiales:

    • Infinity. Valor especial usado en lugar de un número gigante que no cabe en un double de 64 bits, por ejemplo el resultado de la expresión 17/0.
    • NaN. Acrónimo de "not-a-number". Es un valor especial usado cuando una expresión no genera un número válido, como la división 0/0 o tratar de convertir un string no apto a un número como parseInt("cinco").
    • Number.MAX_VALUE. El número más grande representable en un double de 64 bits.
    • Number.MIN_VALUE. El número decimal más pequeño (cercano a cero) representable en un double de 64 bits.
    • Number.NaN. Igual a NaN.
    • Number.POSITIVE_INFINITY. Igual a +Infinity.
    • Number.NEGATIVE_INFINITY. Igual a -Infinity.
    5 pts.

    Escriba un script que genere una tabla con las siguientes columnas: el nombre de la constante, el valor real de dicha constante, el valor que precede a la constante, el valor sucesor de la constante, el resultado de invocar isNaN() con la constante, y el resultado de invocar isFinite() con la constante. En una columna encaebezado escriba cada una de las constantes listadas anteriormente. Llene las celdas de datos de la tabla con el resultado de evaluar cada expresión o función en la columna con la constante de la fila. La tabla tendrá una estructura similar a la siguiente.

    ConstanteValorPredecesorSucesorisNaN()isFinite()
    InfinityInfinityInfinityInfinityfalsefalse
    NaN...............
    Number.MAX_VALUE...............
    ..................
    Number.NEGATIVE_INFINITY-Infinity-Infinity-Infinityfalsefalse
    5 pts.

    Agregue dos filas más a la tabla del ejercicio anterior. La primera con una expresión aritmética que genera un valor real, y la segunda que genere un valor indefinido.

    Cadenas de caracteres (strings)

    Las cadenas literales en JavaScript se encierran entre comillas dobles o simples y se pueden anidar estos separadores dentro de la cadena. Ya que es común escribir código HTML dentro de JavaScript y viceversa, es conveniente que el desarrollador adquiera el hábito de uniformar las comillas para cada cual. El siguiente ejemplo utiliza comillas dobles para valores de atributos de (X)HTML y comillas simples para strings en JavaScript:

    Thanks]]>

    Igual que en C/C++, JavaScript emplea secuencias de escape iniciadas en backslash (\) para anular el efecto de un carácter especial del lenguaje de progamación, tales como \n para el cambio de línea, \r para el retorno de carro, \" para comillas dobles, \' para apóstrofe o comilla simple, \0 para el carácter nulo y \\ para la barra invertida (backslash). Se puede utilizar el backslash frente a un cambio de línea para continuar un string en varias líneas si el intérprete de JavaScript soporta EcmaScript 5, lo cual ocurre en la mayoría de navegadores modernos. El js_newline_scape muestra una cadena multilínea.

    
      var str = 'Cada una de estas líneas\n\
        tiene dos cambios de línea\n\
        el primero es parte del string,\n\
        el segundo es ignorado por JavaScript.'
    
      str = str.replace(/\t/g, '');
      document.write('
    ', str, '
    '); ]]>
    Se puede continuar un string en varias líneas anulando el cambio de línea con un carácter de escape (\). Correr este ejemplo.

    La línea 7 del js_newline_scape emplea expresiones regulares para quitar los tabuladores que son parte del string, y el resultado es asignado al string mismo. Esta asignación debe hacerse obligatoriamente si se quiere reflejar el cambio en el string original, ya que todos los string en JavaScript son inmutables, es decir, ninguna operación puede modificar los caracteres de un string ya que son de sólo lectura.

    En JavaScript las cadenas de caracteres o strings son un tipo de datos atómico, no un arreglo de caracteres. De hecho JavaScript no tiene el concepto de carácter (char) como sí ocurre en otros lenguajes de programación. Un carácter se representa como un string de longitud 1. El método str.charAt(i) permite obtener un string con el carácter que está en la posición i de str, donde el índice i está basado en cero, es decir, 0 representa el primer carácter de la cadena. El siguiente código muestra varias operaciones con strings:

    var visitorName = 'Chema';
    var str = 'Bienvenido ' + visitorName;       // concatenación de textos
    var len = str.length;                        // longitud de cadena
    var lastChar = str.charAt(str.length - 1);   // obtener un carácter de la cadena
    var sub = str.substring(6, 4);               // obtiene 'nido'
    var i = str.indexOf('e');                    // la posición de la primera letra 'e' en str (2)
    var dbg = 'i = ' + i;                        // concatenación con conversión, genera 'i = 2'
    

    El operador de suma (+) cuando alguno de sus operandos es una cadena, hace concatenación. En ECMAScript 5, el operador [] permite acceder a un carácter específico del string de la misma forma que el método str.charAt(). Debe tenerse claro que ambos retornan un nuevo string con el carácter solicitado, por lo que el original no se puede modificar.

    15 pts.

    Escriba un poema de su agrado (o cualquier otro texto con varios párrafos) en una variable string de JavaScript. Separe cada verso por un cambio de línea ('\n') y cada estrofa por dos cambios de línea ('\n\n').

    Imprima el poema dos veces. La primera vez en orden natural, reemplazando los cambios de línea por elementos br y las estrofas por párrafos (p).

    La segunda vez imprima las estrofas (no las líneas que lo componen) en orden inverso en el documento. Para hacer notorio al lector que las estrofas están en orden, o en orden inverso, imprima el número de la estrofa dentro de un elemento span. Si gusta puede escribir el texto de la estrofa dentro de otro elemento span, ambos dentro del párrafo p. Con estilos CSS haga a este número visiblemente grande y ubicado a la izquierda o derecha de la estrofa y deseablemente detrás del resto del texto (propiedad z-index) si hay intersección entre ambos. La siguiente imagen muestra una captura de pantalla de un ejemplo de poema invertido.

    Conversiones entre números y strings

    Cuando un número aparece en un contexto donde se requiere un string, JavaScript lo convierte automáticamente. Por ejemplo, si uno de los operandos de + es una cadena y el otro es un número, el operador + actuará como el operador de concatenación y convertirá el número en una cadena, como se hace en la línea 3 del js_number_to_string_operator_plus.

    ', text, '

    \n');]]>
    El operador de concatenación convierte números a cadenas automáticamente. Correr este ejemplo.

    Las conversiones explícitas se pueden hacer con el constructor String(numero), y varios métodos de la clase Number: numero.toString(base), numero.toFixed(decimales), numero.toExponential(decimales) y numero.toPrecision(decimales). Ejemplos:

    Conversión explícita de números a string. Correr este ejemplo.
    5 pts.

    Pruebe todas las expresiones que aparecen en el js_number_to_string_operator_plus y js_number_to_string_explicit en el intérprete de JavaScript de su navegador. Por ejemplo, Chrome provee una Consola de JavaScript (Ctrl+Shift+J ó Cmd+Opt+J), donde puede introducir sentencias que serán evaluadas "en vivo". Sugerencia cognitiva: escriba cada expresión manualmente, en lugar de copiarla y pegarla. Al final, copie los resultados que haya obtenido en la consola en un archivo de texto.

    Esta consola además reporta errores gramaticales o de ejecución en el código fuente, por lo cual es importante revisarla constantemente mientras se está desarrollando en JavaScript. Mantenga el hábito de probar cada ejemplo de este capítulo en dicha consola.

    En la dirección opuesta, cuando un string se utiliza en un contexto donde se requiere un número, será traducido automáticamente por JavaScript, por ejemplo:

    var product = "21" * "2";  // product == 42.
    

    Con la notación anterior no se podrá sumar un string a un número con el operador +, ya que será interpretado como concatenación. El constructor Number(str) convierte el string str en un número, siempre que str tenga formato de número en base 10 y no inicie con espacios en blanco. Las funciones globales parseInt(str,base) y parseFloat(str,base) son más flexibles, y asumen que str está en base base (10, si se omite) y lo convierten en un número entero o real respectivamente. Ejemplos:

    Conversión explícita de string a números

    Si la cadena a convertir inicia con "0x" se interpreta que está en hexadecimal. Si inicia con 0 su resultado es indefinido, ya que algunas implementaciones podría interpretar octal o decimal, por lo que es conveniente siempre especificar la base como segundo parámetro de parseInt(). Si no se puede convertir a un número, estas funciones retornan NaN.

    Booleanos

    Los valores booleanos sólo pueden contener los valores literales false o true. Cuando se usa un booleano en un contexto numérico, se convierten automáticamente a los valores respectivos 0 y 1. Si se usan en un contexto string, JavaScript los convierte implícitamente a las cadenas "false" y "true". Los valores especiales NaN, null, undefined y la cadena vacía ("") siempre se convierten a false; todos los demás a true (como Infinity). Para hacer explícita la conversión, es recomendable emplear la función constructora Boolean():

    var x_as_boolean = Boolean(x);
    
    5 pts.

    ¿Qué valor y tipo de datos generan las siguientes expresiones en JavaScript? Escriba sus repuestas en un documento de texto o una tabla HTML (puede tomar el código fuente de la que está abajo). Después de responder la columna "Predicción", utilice la consola de JavaScript de su navegador para evaluar cada expresión y anotar en la columna "Resultado" la respuesta que obtuvo. ¿Qué porcentaje de acierto obtuvo?.

    ExpresiónPredicciónResultado
    1var a = 0/0 == NaN;
    2var b = a == false;
    3var c = Number(a);
    4var d = Number(b);
    5var e = String(a);
    6var f = String(b);
    7var g = Boolean('true');
    8var h = Boolean(' True ');
    9var i = Boolean('false');
    10var j = Boolean('0');
    11var k = Boolean(0);
    12var l = Boolean(-1);
    13var m = Boolean(null);
    14var n = Boolean('');
    15var o = Boolean(' ');

    Funciones

    El programador puede declarar sus propias funciones con la palabra reservada function, el nombre opcional de la función, los parámetros sin tipos entre paréntesis ( ), y el cuerpo de la función entre llaves { }. Las funciones en JavaScript son un tipo de datos más, por ende, una función es un valor; así, las funciones se pueden almacenar en variables, miembros de objetos, arreglos, y pasarse por parámetros en una forma más natural que en C/C++. Cuando una función se asigna a un objeto como un miembro, recibe el nombre especial de método. En caso de asignarse a una variable, puede omitirse el nombre de la función, lo que en JavaScript se llama función literal o función lambda en homenaje al lenguaje Lisp que fue uno de los primeros en permitir funciones sin nombre:

    Tres formas de declarar una función en JavaScript

    Una tercera forma de definir una función es pasar sus argumentos y cuerpo como strings a la función constructora Function(), lo cual es poco usado e incluso, menos eficiente. Cuando el valor de una variable es una función, se puede invocar ésta usando el operador paréntesis () tras el nombre de la variable, como se hizo en la línea 11 del js_function_declaration_types con square2.

    5 pts.

    Programe la función factorial recursivamente. Imprima en una lista no ordenada de (X)HTML el factorial de los primeros 20 naturales. ¿Qué sucede si llama su función con un número muy grande o con parámetro no numérico?

    Objetos

    Un objeto es una colección de valores nombrados, que usualmente se les refiere como propiedades, campos o miembros del objeto, y se les accede utilizando el operador punto. Por ejemplo:

    image.width
    image.height
    document.myform.button
    document.write("write es un método: una propiedad cuyo tipo de datos es una función");
    

    El operador punto permite acceder a las propiedades utilizando identificadores. Pero JavaScript permite también usar cadenas de caracteres para acceder a las propiedades, con el operador corchetes []. Esta segunda notación es mucho más flexible ya las cadenas de caracteres pueden ser el resultado de evaluar una expresión. De esta forma, el operador corchetes permite emplear los objetos de JavaScript como arreglos asociativos, también llamados mapas (maps) o tablas de dispersion (hash). Ejemplos:

    image["width"]
    image["height"]
    document["myform"]["button"]
    document["write"]("write es un método: una propiedad cuyo tipo de datos es una función");
    

    Los objetos se crean llamando funciones constructoras con el operador new, después de lo cual se usan como de costumbre. Estos objetos son almacenados en memoria dinámica por el navegador, el cual incorpora un recolector de basura (garbage collector), de tal forma que ahorra al programador la responsabilidad de liberar la memoria de cada objeto creado.

    Los objetos se crean con el operador new y funciones constructoras

    En la línea 4 del js_new_operator el objeto point se creó como un objeto vacío, y sus propiedades se fueron agregando luego con el operador de asignación (líneas 5 y 6). Existe una notación para definir objetos literales, con o sin propiedades, útil para inicializaciones:

    Notación para escribir objetos literales en JavaScript

    Las llaves {} en una sección de declaración de variables (var) de JavaScript indican la creación de un objeto literal. Los nombres de las propiedades pueden declararse como identificadores (como se hizo con property1 en js_literal_object_notation) o como strings (como se hizo con "property2" en js_literal_object_notation). Los valores de cada propiedad pueden ser de cualquier tipo de datos de JavaScript (booleano, numérico, string, función, arreglo, u objeto), sea como valores literales o como resultado de una expresión aritmética. Cada propiedad debe separarse por una coma, y no por punto y coma. Las declaraciones de objetos literales se pueden anidar como se hizo con rectangle en el js_json_ex1.

    Notación de objetos de JavaScript

    La notación presentada en el js_json_ex1 para escribir objetos literales, es importante, y recibe el nombre de JavaScript Object Notation (JSON). Es ampliamente usada para representar datos y funciones que deben ser intercambiados entre el servidor web y el navegador, en bases de datos orientadas a documentos, y un número creciente de tecnologías. Más adelante se completará esta notación para representar arreglos.

    Cada vez que JavaScript evalúa un objeto literal, se crea un objeto diferente, debido a que los valores de las propiedades pueden ser expresiones que cambian de una evaluación a otra, por ejemplo, en un ciclo. El js_literal_objects muestra un programa JavaScript que construye una tabla (X)HTML con una lista de personas ficticias generadas aleatoriamente a partir de un arreglo de nombres y apellidos. El programa consta de dos declaraciones de variables globales, cuatro declaraciones de funciones y una invocación de función (línea 37). Al ser invocada, la función imprimirPersonas() recibe el número deseado de personas y por cada una de ellas invoca a crearPersona(), la cual crea un objeto literal (líneas 13 a 17), lo almacena en una variable local, y luego retorna una referencia a dicho objeto. La función imprimirPersonas() recibe el objeto creado (línea 33) y lo pasa por parámetro a imprimirPersona() quien genera la línea correspondiente en la tabla. Es importante notar que en cada iteración del ciclo la evaluación del objeto literal (líneas 13 a 17) genera una persona distinta, y no el mismo objeto, incluso aunque el valor de sus propiedades no cambiaran.

    ', numero, '',persona.nombre,
          '', persona.edad, '', persona.ingreso, '');
    }
    
    // Crea e imprime en una tabla (X)HTML la cantidad solicitada de personas aleatorias
    function imprimirPersonas(cantidad)
    {
       document.write('');
       for ( var i = 1; i <= cantidad; ++i )
          imprimirPersona( crearPersona(), i );
       document.write('
    '); } imprimirPersonas(300); ]]>
    Cada vez que se evalúa un objeto literal, JavaScript crea un nuevo objeto. Correr ejemplo completo.

    Si un objeto se emplea en un contexto booleano, se traduce a true si el objeto no es null. Si un objeto aparece en un contexto string se invocará su método toString() para hacer la conversión. Si un objeto aparece en un contexto numérico, JavaScript invocará valueOf() para hacer la conversión. El desarrollador puede sobrescribir estos métodos en sus propios objetos, lo cual es una práctica recomendada de programación.

    10 pts.

    Escriba un objeto Círculo, Triángulo y Rectángulo. En cada uno de ellos almacene su posición y dimensiones. Escoja valores arbitrarios para cada uno de ellos. Provea dos métodos en cada objeto, uno para calcular el perímetro y otro para el área. Haga un programa en JavaScript que imprima para cada una de las tres figuras: su tipo, posición, dimensiones, perímetro y área. Para este ejercicio no tiene que dibujar las figuras geométricas, sino imprimir sus coordenadas y resultados numéricos en una tabla como la de abajo.

    #FiguraPosición/DimensionesPerímetroÁrea
    1Círculocentro(..., ...) radio(...)......
    2Triánguloa(..., ...) b(..., ...) c(..., ...)......
    3Rectánguloa(..., ...) b(..., ...)......

    Nota: si A, B y C son los vértices de un triángulo, su área y perímetro se pueden obtener mediante:

    $$ \mathit{area}=\left|\frac{A_x\left(B_y-C_y\right)+B_x\left(C_y-A_y\right)+C_x\left(A_y-B_y\right)}{2}\right| $$

    $$ \mathit{perimeter}=\sqrt{\left(A_x-B_x\right)^2+\left(A_y-B_y\right)^2}+\sqrt{\left(A_x-C_x\right)^2+\left(A_y-C_y\right)^2}+\sqrt{\left(B_x-C_x\right)^2+\left(B_y-C_y\right)^2} $$

    5 pts.

    Agregue otro triángulo a la colección de figuras hechas en el ejercicio anterior. Intente reutilizar el código de los métodos del primer triángulo en lugar de duplicarlo (consulte la sección Funciones). Haga que su nuevo triángulo aparezca en la cuarta línea de la tabla. Sugerencia: puede verificar el área de sus triángulos contra esta aplicación.

    Arreglos

    En JavaScript un arreglo es una colección de datos enumerados. Se acceden con un índice entero, basado en 0, escrito entre corchetes tras el nombre del arreglo. El siguiente ejemplo obtiene el ancho en pixeles de la segunda imagen en el documento:

    document.images[1].width
    

    Los arreglos pueden tener datos heterogéneos, de cualquiera de los 7 tipos de datos de JavaScript. Así un elemento del arreglo puede contener otro arreglo. Los arreglos se crean con el constructor Array() y sus elementos se pueden agregar simplemente asignándolos a sus índices o bien, como parámetros del constructor Array(); pero si se pasa un único entero a este constructor, de la forma Array(N) se creará un arreglo con N elementos indefinidos. La propiedad length permite acceder al número de elementos en el arreglo. Ejemplos:

    var a = new Array();                // Arreglo vacío, lo mismo que: var a = [];
    a[0] = 1.2;                         // Un elemento es insertado en la posición 0
    a[1] = "JavaScript";                // Un elemento es insertado en la posición 1
    a[2] = true;
    a[4] = { x:1, y:3 };                // La posición 3 tiene un elemento con el valor undefined
    a[5] = function(x) { return x*x; }; // a[5](7) retornará 49
    a[6] = new Array();                 // Elemento a[6] almacena un arreglo vacío
    a[6][0] = -Infinity;                // Inserta un elemento en el arreglo que está en a[6]
    console.log(a.length);              // Imprime la cantidad de elementos en el arreglo: 7
    
    var b = new Array(1.2, "JavaScript", true, { x:1, y:3 });
    console.log(b.length);              // 4 elementos
    
    var c = new Array(10);              // Arrreglo de 10 elementos indefinidos
    console.log(c.length);              // Imprime 10 y no 1
    

    JavaScript permite crear arreglos literales, preferiblemente utilizados para inicialización, y son una lista de valores separados por comas dentro de corchetes, que se asignan secuencialmente empezando en 0. Los elementos también pueden ser indefinidos lo cual se logra omitiendo el valor entre comas:

    var b = [ 1.2, "JavaScript", true, { x:1, y:3 } ];
    
    var matrix = [[1,2,3], [4,5,6], [7,8,9]];           // matrix[2][1] == 8
    
    var base = 1024;
    var table = [base, base+1, base+2, base+3];
    
    var sparseArray = [1,,,,5];
    
    5 pts.

    Almacene las figuras que haya creado en los ejercicios geometric_figures_1 y geometric_figures_2 en un arreglo. Con un ciclo recorra el arreglo imprimiendo cada figura, su perímetro y su área, para generar la tabla resultado.

    30 pts.

    Escriba una función que crea y retorna un objeto figura geométrica aleatoriamente cada vez que se invoca. Llene un arreglo de 20 figuras aleatorias e imprímalas en la tabla como hizo en el ejercicio anterior. Puede apoyarse en los métodos Math.random() y Math.floor() para generar números aleatorios.

    40 pts.

    Represente el inventario de la fig_xml_inventory como una jerarquía de activos en JavaScript Object Notation (JSON). Programe métodos para imprimir cada activo e imprima el inventario en un documento HTML. Haga que cada activo genere un div en el documento, de tal forma que los div mantengan el mismo anidamiento que los objetos de JavaScript. Con estilos CSS agregue bordes y colores a los div para que sea visualmente clara la relación entre estos. La siguiente figura muestra un ejemplo potencial.

    Valores especiales

    El valor especial undefined indica que una variable u objeto fue declarado pero nunca se le ha asignado un valor, y en tal caso, JavaScript la inicializa con el valor especial undefined. Si una función no retorna un valor, JavaScript asume undefined. Si una función se invoca con menos parámetros de los esperados, éstos últimos recibirán el valor undefined. Si lo desea, el programador puede asignar explícitamente undefined a una variable.

    El valor especial null se utiliza para indicar que un objeto sí está declarado e inicializado pero ningún otro valor de su dominio aplica momentáneamente. Aunque ambos, undefined y null sirven para indicar ausencia de valor, undefined debería considerarse como una indicación de error porque un valor se esperaba y no fue provisto; mientras que null como una natural indicación de que una variable no tiene valor. Por ejemplo, si al extraer el último elemento de un arreglo con arr.pop() se obtiene undefined, el programador debe considerar que trató de extraer un elemento de un arreglo vacío; pero si arr.pop() retornó null, el programador sabrá que el arreglo tenía elementos y el último era precisamente el valor null.

    Objetos especiales

    El lenguaje de programación JavaScript provee varios objetos útiles: Date, RegExp, Boolean, Number y String. El objeto Date sirve para obtener y manipular fechas u horas, como se ilustra en el js_date_object.

     25 )
       {
          christmas.setFullYear( now.getFullYear() + 1 );
          text = 'la próxima ';
       }
    
       // Convertir la cantidad de milisegundos que faltan para navidad en dias
       var dias = (christmas.getTime() - now.getTime()) / (1000 * 60 * 60 * 24);
       text = 'Faltan ' + dias.toFixed(0) + ' días para ' + text + 'navidad';
    }
    
    document.write('

    ', text, '

    \n'); ]]>
    Ejemplo de uso del objeto Date. Correr este ejemplo.

    El objeto especial RegExp permite manipular expresiones regulares en JavaScript, siguiendo la misma notación de Perl. [Contenido pendiente: este tema se cubrirá en el futuro].

    Los 7 tipos de datos de JavaScript pueden dividirse en dos grupos: valores primitivos (números, booleanos, strings y valores especiales (undefined y null)), los cuales no pueden tener métodos; y los valores objeto (objetos, arreglos y funciones), los cuales sí pueden tener métodos. Como se dijo, ningún valor primitivo en JavaScript tiene métodos, sin embargo, se puede saber la longitud de un arreglo o convertir un número en un string con métodos, por ejemplo:

    var longitud = 'ácido desoxirribonucleico'.length;
    var num = 777;
    var bin_str = num.toString(2);
    

    Esto es posible ya que JavaScript define tres clases correspondientes a cada uno de los tipos de datos primitivos, llamadas wrapper objects: Number, String y Boolean. Cuando a un valor primitivo se le invoca un método, JavaScript automáticamente construye un objeto temporal de la clase correspondiente y lo inicializa con el dato primitivo, invoca el método y finalmente destruye el objeto temporal. Es decir, cuando se escribe algo como

    var str = "Hola mundo!";
    var len = str.length;
    

    La propiedad length no proviene del string str, sino de un objeto temporal String inicializado con str. Nótese que el objeto String contiene una copia del texto original, y después de usarse, se desecha. Este comportamiento también aplica para los datos primitivos de Number y Boolean.

    5 pts.

    Calcule el tiempo que tarda en ejecutarse todos los scripts en conjunto, que haya programado en una página web con mucho comportamiento. Si lo desea puede descargar una copia de este material de apoyo y modificarla. Sugerencia: guarde la cantidad de milisegundos en un script en el encabezado del documento. En un script al final del documento, presente el resultado al usuario en el pie de página, en milisegundos o segundos (si se tarda más de uno). Es decir, su algoritmo debe ser capaz de ajustar la unidad automáticamente.

    Por valor o por referencia

    En JavaScript algunos datos se manipulan por valor y otros por referencia cuando se copia un dato de una variable a otra, cuando se pasa por parámetro a una función y cuando se compara. Automáticamente JavaScript sigue esta regla: los valores primitivos (booleanos, números, strings y valores especiales) son manipulados por valor; los valores objeto (objetos, arreglos y funciones), son manipulados por referencia. No existe una notación especial para que el programador pueda decidir cuáles manipular por referencia y cuales por valor. Debe ajustarse a las reglas expuestas y tener los cuidados respectivos. Por ejemplo, cuando se invoca a una función, las copias y referencias simplemente se harán de acuerdo al tipo de dato enviado:

    var n = 1;   // Es un número, el literal 1 se copia por valor a n
    var t = n;   // t será un número, copia el valor de n. Un cambio en n no afecta el valor de t
    
    // Los parametros de la funcion no tienen tipo de datos, reciben por valor o referencia
    // de acuerdo a los datos enviados en la invocacion
    function addto(total, value) { total += value; }
    
    // Se invoca con dos numeros, al llamar a addto, total y value tendrán copias por valor
    // así que la funcion no tendra el efecto que quiere conseguir, y por ende, t se mantendra
    // intalterado con su valor 1
    addto(t, n);
    
    // La comparacion se hace por valor, es decir, se comparan byte a byte variables distintas
    if ( t == n ) document.write('Los números son copiados');   // Se evaluará como true
    

    Cuando los datos se manipulan por referencia, se hace una copia de la dirección del objeto. Es decir, se copian, pasan por parámetro y comparan direcciones que apuntan a lo mismo, de forma similar a los punteros C. Por ejemplo:

    // Crea un objeto y su direccion la copia a hoy
    var hoy = new Date();
    
    // Copia la direccion de hoy a navidad, ambas variables refieren al mismo objeto
    var navidad = hoy;
    
    // Modifica al objeto apuntado, por ende, 'hoy' tambien referirá al 25 de diciembre
    navidad.setMonth(11);
    navidad.setDate(25);
    
    // Si se comparan, se hará una comparación de direcciones, y se evaluará como true
    if ( hoy == navidad ) document.write('Hoy es navidad!');
    
    // se crea otro objeto distinto pero con iguales datos
    var navidad2 = new Date(navidad.getFullYear(), 11, 25);
    
    // Esta comparacion evaluara como falsa, ya que tienen direcciones distintas
    if ( navidad == navidad2 ) document.write('La navidad es universal!');
    
    
    // Una funcion recibira por valor o referencia dependiendo de como se le invoque
    function addDays(date, days)
    {
       date.setDate( date.getDate() + days );
    }
    
    // En esta invocacion, date recibira una copia de direccion de navidad y days una copia del
    // literal 6 logrando el efecto deseado para navidad, pero 'hoy' se vera afectado tambien.
    addDays(navidad, 6);
    
    // Esta funcion no provoca el efecto deseado pero ilustra como trabajan las direcciones
    function addDaysB(dateB, daysB)
    {
       var tmpDate = new Date(dateB);
       tmpDate.setDate( tmpDate.getDate() + daysB );
       dateB = tmpDate; // Esto solo modifica la direccion de dateB y no al objeto real
    }
    
    // Al hacer esta invocacion la funcion addDaysB crea otro objeto internamente y lo asigna a su
    // parametro temporal dateB y no a navidad2. Al salir de la función, navidad2 permanece
    // inalterada. Esto también explica cómo actuar cuando no se quiere alterar datos que son pasados
    // por referencia: haciendo copias
    addDaysB(navidad2, 6);
    

    Dado a que los strings son inmutables, se comportan por valor como muestra el js_string_by_value_or_reference:

    Determinar si JavaScript maneja los string por valor o por referencia. Correr este ejemplo.

    Variables

    Una de las primeras diferencias visibles con otros lenguajes como C es que las variables de JavaScript no tienen un tipo de datos, por lo que es perfectamente válido asignarles un valor de un tipo y luego otro de diferente naturaleza:

    var i = 16;
    i = "dieciséis";
    

    Antes de que se pueda usar una variable, debe haberse declarado con la palabra reservada var, o JavaScript declarará una implícitamente; lo cual puede traer efectos secundarios indeseados. En ECMAScript 5 el autor puede incluir la cadena literal 'use strict';. Esta constante literal provoca que en adelante el intérprete sólo cree variables cuando están en una sección var y genere un error en otras circunstancias. La instrucción 'use strict'; además activa otras restricciones acordes a las prácticas sanas de programación, por lo cual se recomienda incluir esta cadena al inicio de todos sus programas JavaScript.

    En la declaración se deben inicializar las variables, sino JavaScript lo hará con el valor undefined. Si una variable se declara dos veces en secciones var distintas y la segunda declaración tiene inicialización actúa como una simple asignación. Se pueden declarar variables en cualquier lugar donde pueda haber una sentencia, y en la primera sección de la cláusula for o for/in.

    // Crea una variable i. Al terminar el ciclo i tendrá el valor 10
    for(var i = 0; i < 10; ++i) document.write(i, '\n');
    
    // No crea otra variable i, sino que reutiliza la existente
    for(var i in obj) document.write(i, '\n');
    

    Cuando se trata de leer una variable que no existe, se genera un error y el navegador detiene la ejecución del script. Si se le trata de asignar algo a una variable inexistente, se creará una variable global implícita. Las variables globales son visibles en cualquier lugar donde haya código JavaScript.

    Las variables locales son aquellas creadas en secciones var en los cuerpos de las funciones, incluyendo a los parámetros. Las variables locales se superponen a las globales. A diferencia de C y Java, JavaScript no tiene diferente alcance (scope) en cada bloque de código. Mejor dicho, los bloques de JavaScript lo definen las mismas funciones y no las parejas { }, así todas las variables de una función comparten el mismo alcance, indiferentemente del nivel de anidamiento de llaves en que se declaren las variables. En el siguiente ejemplo; las variables o, i, j, k comparten el mismo alcance.

    function test(obj)
    {
       var i = 0;                        // i is defined throughout function
       if (typeof obj == "object")
       {
          var j = 0;                     // j is defined everywhere, not just block
          for(var k=0; k < 10; ++k)   // k is defined everywhere, not just loop
          {
             document.write(k);
          }
          document.write(k);             // k is still defined: prints 10
       }
       document.write(j);                // j is defined, but may not be initialized
    }
    

    Las variables locales ocultan las globales, y las locales tienen alcance (scope) de toda la función. Esto puede generar resultados confusos o sorprendentes. Por ejemplo:

    var str = "global";
    function f( )
    {
       alert(str);         // Displays "undefined", not "global"
       var str = "local";  // Variable initialized here, but defined everywhere
       alert(str);         // Displays "local"
    }
    f( );
    

    En la función anterior no se imprime "global" en el primer alert de la línea 4, porque se está usando la variable str local de la línea 5, la cual no ha sido inicializada aún. Este comportamiento equivale al siguiente código:

    var str = "global";
    function f( )
    {
       var str;
       alert(str);         // Displays "undefined", not "global"
       str = "local";      // Variable initialized here, but defined everywhere
       alert(str);         // Displays "local"
    }
    f( );
    

    El consejo de mantener las variables tan locales como sea posible, no aplica para JavaScript. Algunos programadores prefieren incluso declarar sus variables juntas al inicio de cada función JavaScript. Es importante que el programador tenga claro que en JavaScript una variable es global si no aparece en el cuerpo de una función, y que una variable es local si aparece en algún lugar del cuerpo de una función, no importa el nivel de anidamiento de llaves en que se encuentre.

    En JavaScript una variable puede estar declarada o no declarada. Una variable es declarada si el programador lo hace formalmente en una sección var, incluso aunque no sea inicializada (en cuyo caso JavaScript le asigna el valor undefined). Naturalmente una variable no declarada es la que no aparece en una sección var. Intentar acceder a una variable no declarada es siempre un error y el intérprete podría detener la ejecución del script. Sin embargo, el comportamiento de asignar una variable no declarada depende del modo de ejecución del script. En modo estricto se considerará un error, mientras que en modo no estricto (el por defecto), JavaScript creará una nueva variable global, le asignará el valor, y a partir de ese momento se comportará como una variable declarada.

    var x;     // Una variable declarada no inicializada. Su valor es undefined
    alert(u);  // Tratar de leer una variable no declarada es un error
    c = 2413;  // Asignar un valor a una variable no declarada crea una variable global
    

    Cuando se inicia un intérprete de JavaScript, lo primero que hace antes de ejecutar el código fuente, es crear el objeto global (global object), que es un objeto como cualquier otro con la misión de almacenar todas las variables globales que se declaren en el código. Cada vez que se declara una variable global, realmente está declarando una propiedad del global object.

    El intérprete de JavaScript también define convenientemente otras propiedades (variables y métodos) en el global object que son de uso común, como NaN, Infinity, parseInt(), y Math. La palabra reservada this usada en un contexto global (fuera del cuerpo de una función), referencia específicamente al global object. En el caso del navegador, el global object es además la ventana del navegador (window), y se cumple:

    this == this.window == window
    

    Si las variables globales son propiedades de un global object ¿qué son las variables locales? También son propiedades, pero de un objeto temporal llamado call object, el cual se construye en cada invocación de una función, y mantiene juntos los parámetros, variables declaradas en el cuerpo de la función y el código de la misma. Este objeto es el que impide que las variables locales sobrescriban las globales cuando tienen el mismo nombre. Dentro de una función, this hace referencia al call object en lugar del global object.

    5 pts.

    Cree un script en el encabezado head de un documento HTML5. En el primer script cree una variable con su número de la suerte y una función que lo imprime en un párrafo. Cree un segundo script como el último elemento del cuerpo del documento (body).

    Expresiones

    Una expresión es un trozo de código que al evaluarse genera un valor de cualquiera de los 7 tipos de datos de JavaScript. Las expresiones pueden ser tan sencillas como valores literales, hasta expresiones complejas compuestas de varios operadores y operandos.

    Operadores

    Los operadores aritméticos de resta (-), multiplicación (*), división (/) y módulo (%) sólo trabajan con números. Si se usan con operandos de otro tipo de datos, JavaScript intentará convertirlos a números invocándoles el método valueOf(). Ya que todo número en JavaScript es un flotante, la división siempre es real, es decir, no hay división entera como ocurre en otros lenguajes. El operador + actúa como operador de suma si sus operandos son numéricos, y como el operador de concatenación si al menos uno de ellos es string.

    JavaScript tiene dos operadores para determinar semejanza. El operador de igualdad (==) indica si dos valores son el mismo incluso tras hacer conversiones de tipos. El operador de identidad (===) es más estricto y dice que dos valores son idénticos si son iguales y tienen el mismo tipo de datos. Sus opuestos respectivos son el operador de desigualdad (!=) y de no identidad (!==). Por ejemplo:

    "0" ==  false        // produce true  (hace conversiones)
    "0" === false        // produce false (no hace conversiones)
    
    "037.50" ==  37.5    // produce true
    "037.50" === 037.50  // produce false
    

    Los operadores de comparación <, <=, >, >= actúan como de costumbre si sus operandos son del mismo tipo, sino se tratan de convertir a números, y si esta conversión falla se generará NaN, que siempre se evalúa como false en un contexto booleano.

    1 + 2        // Addition. Result is 3.
    "1" + "2"    // Concatenation. Result is "12".
    "1" + 2      // Concatenation; 2 is converted to "2". Result is "12".
    11 < 3       // Numeric comparison. Result is false.
    "11" < "3"   // String comparison. Result is true.
    "11" < 3     // Numeric comparison; "11" converted to 11. Result is false.
    "one" < 3    // Numeric comparison; "one" converted to NaN. Result is false.
    

    Los operadores lógicos son los mismos de C/C++/Java para conjunción (&&), disyunción (||) y negación (!). Pero guardan una diferencia. Los operandos se convierten a Boolean temporalmente para hacer la evaluación del operador, pero el resultado final del operador no es booleano, sino del tipo de datos del último operando evaluado. A esto se le puede sacar ventaja. En el siguiente ejemplo, la variable max adquirirá el primer valor numérico que no sea null en lugar de un valor booleano.

    // If max_width is defined, use that. Otherwise look for a value in
    // the preferences object. If that is not defined use a hard-coded constant.
    var max = max_width || preferences.max_width || 480;
    

    El operador ternario ?: funciona igual que en C. Los operadores de bits (bitwise operators): and (&), or (|), xor (^), not (~), shift left (<<), signed shift right (>>) y shift right with zero fill (>>>), sólo trabajan con enteros de 32 bits y su uso es inusual en JavaScript.

    El operador in recibe al lado izquierdo un string y al derecho un objeto o arreglo. Se evalúa como true si el string es el nombre de una propiedad del objeto al lado derecho, incluso si es heredada. Ejemplos:

    var point = { x:1, y:1 };        // Define an object
    var has_x_coord = "x" in point;  // Evaluates to true
    var has_y_coord = "y" in point;  // Evaluates to true
    var has_z_coord = "z" in point;  // Evaluates to false; not a property of point
    var tstr = "toString" in point;  // Inherited property from Object; evaluates to true
    

    El operador instanceof espera al lado izquierdo un objeto y al lado derecho el nombre de una clase (realmente una función constructora). Evalúa a true si el lado izquierdo (el objeto) es una instancia de la clase o un objeto descendiente de dicha clase.

    var d = new Date();  // Create a new object with the Date() constructor
    d instanceof Date;   // Evaluates to true; d was created with Date()
    d instanceof Object; // Evaluates to true; all objects are instances of Object
    d instanceof Number; // Evaluates to false; d is not a Number object
    
    var a = [1, 2, 3];   // Create an array with array literal syntax
    a instanceof Array;  // Evaluates to true; a is an array
    a instanceof Object; // Evaluates to true; all arrays are objects
    a instanceof RegExp; // Evaluates to false; arrays are not regular expressions
    

    El operador unario typeof genera un string con el nombre del tipo de datos de su argumento a la derecha, que puede o no estar entre paréntesis. Típicos resultados son "number", "string", "boolean", "object" (incluye los arreglos y null), "function" y "undefined" cuando el parámetro no ha sido declarado. Ejemplo:

    typeof undefined      // retorna "undefined"
    typeof false          // retorna "boolean"
    typeof (3 / 1.1)      // retorna "number"
    typeof '0'            // retorna "string"
    typeof {}             // retorna "object"
    typeof []             // retorna "object"
    typeof null           // retorna "object"
    typeof function() {}  // retorna "function"
    
    return typeof value == "string" ? "'" + value + "'" : value;
    

    Ya que typeof retorna "object" para objetos de diversa naturaleza, su utilidad se reduce a saber si su operando es o no de un tipo de datos primitivo. Para saber la clase de un objeto hay que recurrir a otras técnicas como el operador instanceof, o la propiedad Object.constructor, como se verá luego.

    Igual que en C++ y Java, el operador new crea un objeto vacío, invoca un constructor para que lo inicialice, y retorna la dirección de memoria del objeto. Si el constructor no recibe parámetros, puede omitirse sus paréntesis.

    o = new Object;    // Optional parentheses omitted here
    d = new Date();    // Returns a Date object representing the current time
    
    // Una función constructora
    function Point(x, y)
    {
       this.x = x;
       this.y = y;
    }
    
    p = new Point(3.0, 4.0);   // Crea un objeto vacío y lo inicializa con la función constructora
    

    El operador delete intenta eliminar una propiedad de un objeto, un elemento de un arreglo o la variable especificada como operando. Retorna true si la eliminación fue exitosa. Algunas variables o propiedades no pueden ser eliminadas, como las declaradas en secciones var. Si el único argumento de delete no existe, se retorna true. Ejemplos:

    var o = {x:1, y:2};  // Define a variable; initialize it to an object
    delete o.x;          // Delete one of the object properties; returns true
    typeof o.x;          // Property does not exist; returns "undefined"
    delete o.x;          // Delete a nonexistent property; returns true
    delete o;            // Can't delete a declared variable; returns false
    delete 1;            // Can't delete an integer; returns true
    x = 1;               // Implicitly declare a variable without var keyword
    delete x;            // Can delete this kind of variable; returns true
    x;                   // Runtime error: x is not defined
    

    Nótese que el operador delete no trata de eliminar memoria dinámica como ocurre en C++, lo cual se hace en JavaScript con el recolector de basura (garbage collector), no hay otra forma. El delete de JavaScript elimina una propiedad, es decir, deja de existir; no es que se le asigne undefined:

    var my = new Object( );   // Create an object named "my"
    my.hire = new Date( );    // my.hire refers to a Date object
    my.fire = my.hire;        // my.fire refers to the same object
    delete my.hire;           // hire property is deleted; returns true
    document.write(my.fire);  // But my.fire still refers to the Date object
    

    Sentencias

    Una sentencia en un lenguaje de programación es un comando que al ser ejecutado produce un efecto. Un programa es una secuencia de sentencias que se ejecutan una tras otra, sin embargo, el lenguaje de programación provee estructuras de control que permiten ejecutar sentecias condicional o repetitivamente. Las sentencias en JavaScript deben terminar en punto y coma, aunque no es obligatorio. Las estructuras de control condicional son las mismas de C: if, else y switch, como muestra el siguiente ejemplo.

    if (username != null)
       alert("Hello " + username + "\nWelcome to my blog.");
    else if ( askname )
    {
       username = prompt("Welcome!\n What is your name?");
       alert("Hello " + username);
    }
    else
       alert("Hello there");
    

    La estructura de control switch es más flexible que en C. Al ser un lenguaje interpretado, los casos del switch son expresiones, no sólo constantes. El parámetro del switch se compara contra cada case utilizando el operador de identidad ===, hasta encontrar una coincidencia o el default si fue provisto por el programador.

    Una estructura switch en JavaScript

    En muchas situaciones una estructura switch puede ser reemplazada por un arreglo común o un arreglo asociativo (también conocido como tabla de dispersión (hash), o mapa (map)) si trabaja con valores primitivos; o por polimorfismo si el switch trabaja con objetos; lo cual tiene algunas ventajas como mejor mantenimiento del código. Por ejemplo, el mismo efecto del js_switch_normal puede conseguirse con un arreglo asociativo como se muestra en el js_switch_hash.

    Utilizar una tabla de dispersión para reemplazar un switch

    El js_switch_hash construye un objeto normal, llamado methods, cuyas propiedades son referencias a funciones, y que se pueden acceder con el operador punto, por ejemplo methods.ftp(), o con el operador corchetes methods['ftp'](). Ya que la función transfer() (línea 14) recibe el método de transferencia como un string, resulta conveniente utilizar el operador corchetes. La línea 16 pregunta si el objeto methods tiene una propiedad con el nombre del método enviado por parámetro. Si es así, accede a la propiedad con el operador corchetes [], la cual se evalúa como una función, y finalmente con el operador paréntesis () la invoca pasándole el archivo (file) por parámetro.

    Dado a que las funciones transfer_method() son globales, JavaScript las declara ya como propiedades de un objeto global (window en el caso del navegador). De esta forma, el programador podría acceder a ellas directamente como se ve en el js_switch_global_object, en lugar de crear el objeto methods.

    Utilizar el objeto global window como tabla de dispersión

    Como es de esperar, las estructuras de control para reiteración de sentencias de JavaScript son las mismas de C: for, while y do/while. Por ejemplo:

    ');
    ]]>
    Ejemplo del ciclo for en JavaScript. Correr este ejemplo.

    5 pts. Cree una función JavaScript que reciba un número n y retorne un arreglo con los primeros n números de Fibonacci. Utilice su función para crear un arreglo con los primeros 40 números de Fibonacci e imprímalos en una lista ordenada.

    JavaScript provee un tipo de ciclo más, el ciclo for/in, cuya sintaxis es:

    for (property_name in object)
       /* do something with */ object[property_name];
    

    donde property_name se refiere al nombre de una variable, una declaración var, un elemento de un arreglo, la propiedad de un objeto, o incluso una expresión. object se refiere a un objeto o una expresión que evalúa en un objeto. El cuerpo del for/in, se ejecuta una vez por cada propiedad del objeto y en cada iteración, property_name adquiere el nombre de la propiedad y no su valor, es decir, property_name es siempre un string. Para obtener el valor de la propiedad debe entonces utilizarse el operador corchetes [] de la forma object[property_name]. Por ejemplo:

    Recorrer las propiedades de un objeto con el ciclo for/in. Correr ejemplo completo.
    5 pts.

    Utilice un ciclo for/in para imprimir recursivamente los activos del inventario que hizo en el inventory_json.

    Ya que property_name puede ser una expresión arbitraria, cada vez que se itera se podría evaluar de forma diferente. Por ejemplo, este código copia los nombres de un objeto en un arreglo:

    var obj = {x:1, y:2, z:3};
    var arr = new Array( );
    var i = 0;
    for( arr[i++] in obj )
       ;
    
    // Imprime cada nombre en el arreglo
    for(i in arr) alert(i);
    

    No hay forma de especificar en un for/in el orden de recorrido, es dependiente de la implementación de JavaScript; lo único que asegura el estándar es que se recorrerán todas las propiedades enumerables del objeto. Una propiedad es enumerable si es definida por el objeto mismo, es decir, no es heredada de otro objeto.

    100 pts.

    Cree un juego de funciones que cada vez que son invocadas generan un valor aleatorio de uno de los siete tipos de datos de JavaScript: valor especial, booleano, número, string, función, objeto, y arreglo. Por ejemplo:

    function genSpecialValue() { return Math.random() < 0.5 ? null : undefined; }
    function genBoolean() { ... }
    function genNumber() { ... }
    function genString() { ... }
    function genFunction() { ... }
    
    function genObject() { ... }
    function genArray() { ... }
    
    function genRandomValue() { ... }
    

    Cree una función genRandomValue(), que invoca aleatoriamente a cualquiera de las funciones anteriores para retornar un valor aleatorio de un tipo de datos aleatorio. Utilice un arreglo para invocar las funciones y no una estructura de control switch.

    La función genFunction() debe crear una función con un cuerpo diferente cada vez que se invoque. Estudie la función constructora new Function(params, body).

    Modifique genArray() para que genere un arreglo con n elementos aleatorios, cada uno resultado de invocar a genRandomValue().

    Modifique genObject() para que genere un objeto con n propiedades aleatorias. Haga que el nombre de la propiedad sea un string aleatorio generado por genString() (considere si se debe mejor implementar una función genIdentifier()). Haga que el valor de la propiedad sea generado por genRandomValue(). Utilice la notación de corchetes para crear las propiedades del objeto.

    75 pts.

    Provea un juego de funciones de impresión printXXX(), cada una especializada en escribir en el documento un tipo de datos utilizando la notación de objetos de JavaScript (JSON). Por ejemplo printArray(array) y printObject(object). Pueda que una función le puede servir para varios tipos de datos que se comportan de forma similar.

    Debe además proveer una función printValue(value) que recibe por parámetro un valor de cualquier tipo de datos, e imprimirlo en el documento invocando a la función printXXX() correspondiente. Estudie los operadores typeof e instanceof. Note que las invocaciones entre printValue() y las funciones printXXX() deberán generar una recursión en caso de tener objetos o arreglos involucrados.

    Idee algún mecanismo para mantener una indentación impecable en el resultado. Por ejemplo, al imprimir un arreglo con elementos aleatorios, podría verse:

    [
    	8.1,
    	false,
    	{
    		dicob: null,
    		pavuwe:
    			[
    			]
    		gofirute: "hekava",
    	},
    	function anonymous( /**/) { return "gisite"; },
    ],
    

    Note que los identificadores de las propiedades en el ejemplo anterior son textos aleatorios. Sugerencia. Para imprimir una función, conviértala a un string y reemplace los cambios de línea por espacios en blanco utilizando expresiones regulares. Por ejemplo: function.toString().replace(/\s+/g, ' ').

    10 pts. Invoque a su función genArray() o genObject() para generar un arreglo de elementos aleatorios o un objeto con propiedades aleatorias. Imprima el objeto o arreglo como contenido de un elemento pre en el documento. Debe ocurrir que cada vez que se refresque el documento, el navegador genere una estructura de datos distinta, con niveles de composición aleatorios e indentación impecables.

    [Contenido pendiente: Manejo de excepciones (try/catch/finally)].

    Arreglos y funciones como objetos

    En JavaScript los arreglos y las funciones son objetos, y por ende tienen propiedades heredadas de las pseudoclases Array y Function respectivamente. A su vez, estas pseudoclases heredan de Object. Esta sección da una introducción de algunas propiedades que estas clases proveen.

    En JavaScript los arreglos y las funciones son objetos, con propiedades y métodos.

    Propiedades de Object

    Todos los objetos de JavaScript heredan de la pseudoclase Object, y por ende, todos los objetos de JavaScript tienen las propiedades que esta pseudoclase defina. En lo siguiente se presentarán algunas de ellas. Cuando se crea un objeto siempre se guarda una referencia a la función que se utilizó para inicializar el objeto, en la propiedad constructor. Por ejemplo:

    var d1 = new Date();
    d1.constructor == Date    // Se evalúa como true
    

    La propiedad constructor sirve para saber si un objeto es instancia directa de una psudoclase particular, mientras que el operador instanceof sirve para determinar si el objeto es descendiente de una pseudoclase dada. Por ejemplo:

    var d1 = new Date();
    d1.constructor == Date    // true
    d1.constructor == Object  // false
    d1 instanceof Date        // true
    d1 instanceof Object      // true, todo objeto es descendiente de Object
    d1 instanceof Array       // false
    
    var o1 = new Object();
    var o2 = {};
    o1.constructor == Object  // true
    o2.constructor == Object  // true
    o1 instanceof Object      // true
    o2 instanceof Object      // true
    
    var a1 = new Array();
    var a2 = [];
    a1.constructor == Array   // true
    a2.constructor == Array   // true
    a1.constructor == Object  // false
    a2.constructor == Object  // false
    a1 instanceof Array       // true
    a2 instanceof Array       // true
    a1 instanceof Object      // true
    a2 instanceof Object      // true
    
    function f1() {};
    var f2 = function() {};
    var f3 = new Function('', ';');
    f*.constructor == Function // true
    f*.constructor == Object   // false
    f* instanceof Function     // true
    f* instanceof Object       // true
    

    El método toString() heredado de la pseudoclase Object es invocado automáticamente por JavaScript cuando necesita convertir el objeto en un string. La implementación por defecto retorna la cadena "[object Object]" que es poco significativa. Por ende, este método debería ser sobrescrito por clases descendientes.

    El método valueOf() es invocado automáticamente por JavaScript cuando el objeto se utiliza en un contexto numérico. El programador también debería sobrescribirlo para clases propias, si su objeto puede convertirse automáticamente a un número.

    Algunas propiedades y métodos que JavaScript provee por defecto en los objetos, arreglos y funciones.

    Propiedades de Array

    La propiedad más natural de un arreglo es length que indica la cantidad de elementos que hay almacenados en él. De hecho es la principal diferencia entre un arreglo y un objeto tradicional. La tabla js_array_methods muestra una lista de métodos que cada arreglo hereda de la pseudoclase Array. Es importante resaltar que algunos de estos métodos modifican el arreglo directamente.

    Método Detalles
    push(elems) Inserta los elementos enviados por parámetro al final del arreglo. Retorna la cantidad de elementos que quedan en el arreglo.
    [1,2,3].push(9,null) // retorna 5, deja [1,2,3,9,null]
    pop() Elimina y retorna el último elemento del arreglo. Si está vacío, retorna undefined.
    [1,2,3].pop() // deja [1,2]
    unshift(elems) Inserta los elementos enviados por parámetro al inicio del arreglo. Retorna la cantidad de elementos que quedan en el arreglo.
    [1,2,3].unshift(9,null) // retorna 5, deja [9,null,1,2,3]
    shift() Elimina y retorna el primer elemento del arreglo
    [1,2,3].shift() // deja [2,3]
    join(sep) Retorna un string resultado de concatenar todos los elementos en el arreglo, separados por la cadena sep, o comas si se omite.
    [1,2,3].join() // genera "1,2,3"
    [1,2,3].join('; ') // genera "1; 2; 3"
    toString() Está sobrescrito para hacer lo mismo que join().
    [1,[8,9],2].toString() // retorna "1,8,9,2"
    reverse() Invierte el orden de los elementos en el arreglo.
    [1,2,3].reverse() // genera [3,2,1]
    sort(comp) Ordena los elementos en el arreglo de acuerdo a la función comparadora comp(), sino los ordena alfabéticamente invocando toString() a cada uno de sus elementos.
    [7, 200, 81].sort() // genera [200,7,81]
    [7, 200, 81].sort(function(a,b){return a-b;}) // genera [7,81,200]
    slice(i,j) Retorna un nuevo subarreglo con los elementos encontrados desde la posición i hasta j - 1, es decir, el que está en j no se incluye.
    [1,2,3,4,5].slice(1,3) // genera [2,3]
    Métodos de la pseudoclase Array

    El operador corchetes [] se utiliza en JavaScript tanto para acceder a los elementos de un arreglo, como a las propiedades de un objeto. De esta forma, un objeto podría utilizarse para simular un arreglo, almacenando los elementos en propiedades con nombres numéricos ('1', '2', '3', ...), más una propiedad length asignada de manera acorde a la cantidad de elementos alojados en el objeto. Por ejemplo:

    Objetos tipo arreglo. Correr este ejemplo.

    Cada vez que la función generarNombres() del js_array_like_objects_example es invocada, creará un objeto vacío resultado (línea 5), el cual llenará con número aleatorio de propiedades cuyo nombre son precísamente números secuenciales. En la línea 11 le crea una propiedad length y retorna una referencia al objeto. Las líneas 16 a 20 crean uno de estos objetos y lo utilizan como si fuese un arreglo normal. Sin embargo no lo es, hay algunas diferencias importantes, en especial que carece de los métodos heredados de la pseudoclase Array, y por ende el objeto tipo arreglo (array-like object) tiene poca funcionalidad para ser modificado. Es decir, se ha creado un arreglo de "sólo lectura", lo cual es una cualidad importante en JavaScript y ampliamente explotada por los navegadores para acceder al modelo de objetos del documento (DOM, Document Object Model) como se verá adelante.

    Propiedades de Function

    En JavaScript las funciones son objetos y por ende también tienen propiedades. Una función puede ser invocada con igual, menos o más argumentos de los esperados por la función; lo cual no genera un error de sintaxis. Por el contrario, JavaScript permite al programador determinar la cantidad real de parámetros enviados, y por tanto, es fácil implementar funciones que trabajan adecuadamente con cantidades arbitrarias de argumentos.

    Cada vez que se invoca una función, JavaScript llena un objeto tipo arreglo (array-like object) llamado arguments que es accesible desde la función. Como es de esperar arguments.length indica la cantidad de argumentos con que se invocó la función y la expresión arguments[i] accede al argumento i + 1 en la lista. El siguiente es un ejemplo de una función tradicional:

    Cómo determinar la cantidad de parámetros con que se invoca una función

    Como se ve en el ejemplo anterior, la invocación de min() con tres parámetros falla el resultado esperado por el llamador. La función min podría detectar esto con la propiedad length, heredada de Function, la cual indica la cantidad de parámetros especificados en la declaración de la función, tal como lo hizo el programador. Mientras que la propiedad arguments.length indica la cantidad de argumentos con que se hizo una invocación de la función. De acuerdo al js_function_arguments1, min.length siempre es dos, incluso aunque no se invoque la función nunca; mientras que el valor de arguments.length puede variar en cada invocación de la función. Cuando estas dos cantidades difieren, el programador puede saber que se ha invocado la función con menos o más argumentos de los esperados y reaccionar de alguna forma, por ejemplo:

    Una función que exige un número estricto de argumentos. Correr este ejemplo.

    Sin embargo, en JavaScript es fácil escribir una función que trabaje naturalmente con un número arbitrario de parámetros, como se ve a continuación.

    Una función que recibe un número arbitrario de argumentos. Correr este ejemplo.
    10 pts.

    Escriba una función que puede recibir una cantidad arbitraria de parámetros y calcula su promedio. Si es invocada sin parámetros retorna undefined. Llame su función con cero, uno, dos y más parámetros e imprima el resultado en el documento. Compruebe que los resultados sean correctos.

    Ya que una función es un objeto, puede tener propiedades, como la propiedad length que es creada por la pseudoclase Function, y el arreglo arguments visto anteriormente. El programador también puede crear sus propias propiedades, de la misma forma que se hace con cualquier otro objeto. Las propiedades que el programador defina tendrán el efecto de ser "variables estáticas" de la función. El siguiente ejemplo muestra una función que reporta el número de veces que ha sido invocada.

    countCalls() ha sido llamada ' + ++countCalls.count + ' veces

    '); } countCalls(); // Imprime "countCalls() ha sido llamada 1 veces" countCalls(); // Imprime "countCalls() ha sido llamada 2 veces" countCalls(); // Imprime "countCalls() ha sido llamada 3 veces" ]]>
    Simular una variable estática dentro de una función. Correr este ejemplo

    Pseudoclases

    JavaScript no tiene el concepto de clase como sí C++ o Java, sino que las clases se simulan con funciones inicializadoras, objetos y prototipos de objetos. Una función constructora o función inicializadora es una función cualquiera que recibe un objeto por parámetro this y le crea propiedades y métodos. Por ejemplo:

    Una función constructora para simular una clase Rectángulo

    La función Rectangle() del js_constructor_function es una función global como cualquier otra, y por ende, es una propiedad del objeto global (window, en caso de los navegadores web). Si se invoca directamente, el valor de this será el objeto global (window) y las líneas 5 y 6 crearán en él dos nuevas propiedades width y height (si no existen ya), y la línea 9 crea otra propiedad más que almacena una función. Como se puede deducir, invocar una función constructora directamente carece de sentido.

    Las funciones constructoras deben ser invocadas con el operador new. Este operador hace lo siguiente. Crea un objeto vacío, sin propiedades. Invoca a la función constructora pasándole el objeto vacío por parámetro para que lo incialice. La función constructora recibe entonces el nuevo objeto en su parámetro this y crea en él las propiedades esperadas. Una vez que la función constructora haya terminado su ejecución, el operador new retorna la dirección de memoria del nuevo objeto inicializado.

    var rect1 = new Rectangle(2, 4);    // rect1 = { width:2, height:4 };
    var rect2 = new Rectangle(8.5, 11); // rect2 = { width:8.5, height:11 };
    document.write("Area of rect2: " + rect2.area() ); // Imprime "Area of rect2: 93.5"
    

    Todos los objetos que sean inicializados con la función Rectangle() tendrán un width y un heigth, el desarrollador puede utilizar con confianza estas propiedades. La función constructora no debe retornar un valor, ya que reemplazará el resultado de la expresión new. Nótese que nunca hubo una clase, sino una función constructora y objetos tradicionales que son inicializados con ella. Por esto se les llama pseudoclases y la función constructora es quien da nombre a la pseudoclase.

    Como es de esperarse, todos los objetos inicializados con Rectangle() tienen su propia copia independiente de width y height. Esto implica que en el ejemplo anterior, si a rect2.width se le asigna otro valor, no afectará al valor de rect1.width; como podría esperarse. Sin embargo, esto mismo ocurre con los métodos: cada objeto inicializado con la función constructura Rectangle() tendrá su propia copia independiente del método area(), lo cual es ineficiente. Esta redundancia se elimina con los objetos prototipo.

    Todas las funciones que el programador defina, tendrán automáticamente otra propiedad llamada prototype creada por Function, de la misma forma que length y arguments. La propiedad prototype es un objeto, definido como una "variable estática" y por tanto, todas las invocaciones a la función tendrán acceso al mismo prototype.

    La especificación ECMAScript exige a cada intérprete de JavaScript implementar el siguiente comportamiento. Cuando se intenta acceder a una propiedad prop en el objeto obj, de la forma obj.prop u obj['prop'], el intérprete buscará si obj tiene una propiedad prop declarada en él, y en tal caso la usará. De lo contrario, el intérprete buscará la propiedad prop en el objeto prototipo de obj, es decir, en obj.prototype.prop; si está declarada la usará, de lo contrario buscará la propiedad en el prototipo del prototipo (obj.prototype.prototype.prop), y así recursivamente hasta encontrar la propiedad o hasta que un prototipo sea null.

    En otras palabras. Si el intento de acceder a la propiedad obj.prop es exitoso, es porque obj tiene una propiedad prop, o alguno de los prototipos de obj define la propiedad prop. Este comportamiento es aproximadamente el mismo que el logrado por la herencia de clases, y es la cadena de prototipos es el mecanismo que JavaScript utiliza para simular herencia.

    Cada vez que se invoca el operador new con una función constructora, éste implícitamente crea una propiedad prototype al nuevo objeto y hace que apunte al prototype de la función constructora. De esta forma, cualquier propiedad que sea definida en el objeto prototipo de la función constructora (o pseudoclase), será compartida por todos los objetos inicializados con dicha pseudoclase. El siguiente pseudocódigo explica lo que hace el operador new internamente:

    // El programador define una función constructora
    function Constructor(a,b) { this.prop1 = a; this.prop2 = b; }
    
       // La pseudoclase Function inserta una propiedad length en la función implícitamente
       Constructor.length = 2;
    
       // La pseudoclase Function inserta una propiedad prototype en la función implícitamente
       Constructor.prototype = {};
    
    
    // El programador crea un nuevo objeto con su función constructora
    var obj1 = new Constructor(a,b);
    
       // El operador new hace esto internamente:
    
       // 1. Crea un objeto vacío
       var newObject = {};
    
       // 2. Crea una propiedad prototype en el objeto que apunta al prototipo de la función
       newObject.prototype = Constructor.prototype;
    
       // 3. Invoca a la función constructora para que inicialice el nuevo objeto, la cual
       // creará las propiedades prop1 y prop2
       Constructor.call(newObject, a, b);
    
       // 4. Retorna el objeto recién inicializado
       return newObject;
    
    // obj1 tendrá al final las siguientes propiedades:
    obj1.prop1
    obj1.prop2
    obj1.prototype
    

    En resumen, cualquier propiedad asignada al objeto Constructor.prototype, será automáticamente una propiedad compartida por todos los objetos construidos con la función Constructor, incluso, aunque dicha propiedad sea asignada después de que los objetos fueron creados. De esta forma, las propiedades creadas por la función constructora directamente en el objeto serán copias independientes en cada objeto, y las propiedades creadas en el prototipo de la misma, serán propiedades compartidas por todos los objetos (lo que en C++ y Java se conoce como miembros estáticos). Por ejemplo:

    // Construye un rectángulo. Recibe un objeto en el parámetro oculto this
    function Rectangle(w, h)
    {
       // Cada objeto tendrá una copia independiente de estas propiedades
       this.width = w;
       this.height = h;
    }
    
    // Este método será compartido por todos los objetos creados con new Rectangle()
    Rectangle.prototype.area = function() { return this.width * this.height; }
    

    Nótese que el método area() no se definió dentro de la función constructora. Si eso se hubiera hecho, se haría la asignación por cada rectángulo creado durante la ejecución del programa, lo cual es ineficiente.

    El prototype es el lugar ideal para definir métodos, constantes y variables compartidas por todos los objetos de una misma pseudoclase. El programador querrá la mayor parte del tiempo tratar estas propiedades como de sólo lectura. Si modifica una propiedad en el prototipo directamente, el cambio afectará a todos los demás objetos inmediatamente; pero si intenta modificar la propiedad a través de un objeto cualquiera, creará una nueva propiedad en ese objeto que oculta la del prototipo. Por ejemplo:

    Conflicto de propiedades en el objeto y el prototipo. Correr este ejemplo.

    Idealmente cuando un programador define una pseudoclase, debe redefinir algunos métodos heredados de la pseudoclase Object. El método toString() debe regresar una representación "string" del objeto. Opcionalmente puede redefinir el método parse(). Si su pseudoclase se puede convertir en un valor primitivo, implemente también valueOf().

    80 pts.

    Escriba una jerarquía de pseudoclases (funciones constructoras) que generen un documento HTML válido de longitud y estructura aleatoria. Por ejemplo, comience con la pseudoclase Document. Su función constructora crea las propiedades de un documento típico: el encabezado y el cuerpo, los cuales son a su vez otros objetos construidos con pseudoclases.

    La función constructora de Body crea un arreglo de una cantidad aleatoria de elementos hijos escogidos también aleatoriamente. Para efectos de este ejercicio, basta con la siguiente jerarquía.

    Document: Header, Body
    Header: Style
    Body: (Paragraph|Heading|List)+
    List: ListItem+
    ListItem: Text|Paragraph+|List
    

    De esta forma cada elemento de su jerarquía tendrá al menos: un arreglo de elementos hijos (llámese children); y un método print() que imprime el elemento usando document.write(), y propaga el llamado a todos sus hijos. El método print() debe declararse en el prototipo de la función constructora para que sea compartido por todos los objetos de la misma pseudoclase.

    Escriba un documento HTML que cree un objeto Document y llame su método print(), el cual debe imprimir el cuerpo del documento. Sugerencia, puede utilizar el siguiente ejemplo:

    
    
    
       Random document
       
       
    
    
    
       
    
    
    ]]>
    40 pts.

    Implemente en su jerarquía de elementos una pseudoclase Style que es hijo de Header y que se encarga de generar estilos CSS aleatorios en el documento, de tal forma que al refrescar, la apariencia del mismo sea compleamente aleatoria. Para esto, agregue un método printHeader() a su pseudoclase Document, el cual invoca al print() de Header y éste al de Style.

    Programación del navegador (el objeto window)

    JavaScript es un lenguaje genérico que cualquier software puede implementar para permitir al usuario un medio de automatizar tareas del software mismo. Aunque el número de sistemas que implementan JavaScript crece en el tiempo, han sido los navegadores web el ejemplo clásico. El navegador web utiliza el lenguaje de programación JavaScript para exponer cierta funcionalidad al autor de un sitio web, quien debe aprovecharla sólo para mejorar la experiencia del usuario con su obra, haciéndole más fácil obtener o transmitir información. Por ejemplo, creando efectos visuales que guíen al usuario hacia lo busca; ordenando los valores de una tabla para ayudarle a encontrar lo que necesita, ocultado o mostrando información que le es o no de interés, o intercambiando información con el servidor web de tal forma que el usuario no se confunda con una recarga completa de la página.

    Ha ido ganando popularidad una práctica de programación llamada Unobtrusive JavaScript (JavaScript no impertinente). Este paradigma sustenta que JavaScript no debería tratar de llamar la atención a sí mismo. No consiste en una variación del lenguaje, sino en un conjunto de prácticas recomendadas, por ejemplo:

    El ambiente de desarrollo del navegador

    Utilizando JavaScript, el navegador pone a disposición del autor un conjunto de objetos que permiten manipular ventanas, cambiar el URL, modificar el contenido o estilo del documento, comunicarse con el servidor web, y otras operaciones útiles.

    El objetivo primordial de un navegador web es desplegar al usuario documentos (X)HTML en una ventana. De ahí nacen los dos objetos más importantes para el programador: la ventana del navegador (window), la cual contiene al documento web (document) del autor.

    El objeto window es quizá el más importante, porque no sólo es un simple objeto, es el objeto global. Todas las propiedades del objeto global son variables globales, y viceversa: las variables globales que el programador defina se crearán como propiedades del objeto global window. Así, las dos siguientes declaraciones fuera del cuerpo de una función hacen esencialmente lo mismo:

    var answer = 722;
    window.answer = 722;
    

    De lo anterior se obtiene que da lo mismo escribir window.document que simplemente document. Dicho de otra forma, el objeto window es el más importante porque todos los demás objetos que existen se acceden a através de él, como se ve en la siguiente jerarquía parcial:

    window
       parent
       top
       navigator
       location
       history
       screen
       document
          anchors[]
          links[]
          images[]
          applets[]
          forms[]
             elements[]
    

    La jerarquía que nace del objeto document ha sido estandarizada por el Consorcio Web (W3C) en lo que se llama Document Object Model (DOM), de tal forma que permite a los programadores JavaScript escribir código portable entre navegadores para manipular el documento y sus estilos.

    Como se indicó al iniciar este capítulo, el código JavaScript puede correr en cuatro lugares: en un elemento script, en un archivo .js externo, en atributos manejadores de eventos y en el pseudoprotocolo javascript:. Todos comparten el mismo objeto global window y su descendencia; por ende, cualquier propiedad definida en uno de estos lugares, es accesible en todos los demás. En el siguiente ejemplo, la función global genRandom() es definida en el primer script y usada en el segundo script.

    
    
       Global properties
       
    
    
    
       

    Su número de la suerte es: .

    ]]>
    Variables globales son propiedades del objeto window. Correr este ejemplo.

    El modelo de ejecución de JavaScript

    El código almacenado en los elementos script se ejecuta sólo una única vez: cuando el documento (X)HTML es cargado en el navegador. Una vez que se ha completado la carga, la interacción se realiza mediante eventos. Cuando ocurre un evento, normalmente generado por el usuario, el navegador puede invocar código JavaScript del autor que reaccione al evento, el cual se asocia al elemento que genere eventos a través de atributos intrínsecos. En el siguiente ejemplo, cuando el usuario hace click en la imagen se invoca el método next() del objeto window.player, y mientras el mismo botón se mantiene presionado, se invoca el método forward() del mismo objeto.

    <img onclick="player.next();" onmousedown="player.forward();" src="img/button_next.svg">
    

    El modelo de ejecución de código JavaScript sigue esta regla. El código que aparece en los elementos script es ejecutado en el mismo orden en que aparecen, durante la carga (parsing) el documento web. Cuando un elemento script termina de ejecutarse, es reemplazado por su salida, la cual es el resultado de las posibles invocaciones a document.write() que se hayan hecho. Inmediatamente el navegador continúa analizando esta salida como cualquier otro código (X)HTML, y posteriormente el resto del documento web.

    Una vez que el documento ha terminado de analizarse, todos los elementos script se habrán ejecutado y el contenido externo, como imágenes o sonidos, habrá sido cargado; el navegador dispara el primer evento: onload. El código manejador de este evento se escribe como valor del atributo onload del elemento body. El código ejecutado en este punto, puede hacer modificaciones libremente sobre la estructura del documento, ya que éste se encuentra totalmente cargado y analizado (parsed); pero no debe invocar a document.write(), ya que hará algo inesperado, como reemplazar el documento por completo.

    Después de cargar el documento, correr los elementos script y atender el evento onload, el navegador entra en la fase de manejo de eventos (event-driven phase), ejecutando el código JavaScript que se haya asociado a los atributos intrínsecos según los vaya disparando el usuario. Estos manejadores de eventos tampoco deben invocar a document.write(), ya que construirán un nuevo documento y reemplazarán el actual.

    Finalmente, cuando el usuario abandona la página, el browser dispara el evento onunload también de body, dando una oportunidad final al código JavaScript de correr. Este debe ser eficiente y silencioso, por ejemplo para hacer alguna limpieza necesaria, evitando demoras que confundan al usuario. La siguiente tabla resume los eventos intrínsecos que el autor dispone para mejorar la comunicación con el lector.

    Evento Descripción
    onclick onclick se dispara cuando el usuario hace click sobre el elemento. Si onclick retorna false, el browser no efectúa la operación por defecto asociada al elemento, por ejemplo, no seguirá el hiperlink en caso de un enlace (a), o no enviaría un formulario en caso de un botón submit.
    onmousedown, onmouseup onmousedown es disparado cuando el usuario presiona el ratón sobre un elemento y onmouseup cuando suelta el botón del ratón. Si ambos eventos ocurren sobre el mismo lugar de un elemento, se generará un onclick. La mayoría de elementos (X)HTML implementan estos dos eventos.
    onmouseover, onmouseout onmouseover se dispara mientras el cursor del ratón está sobre un elemento (X)HTML y onmouseout cuando sale de él.
    onchange El manejador onchange se dispara en los elementos que permiten ingresar texto, como input, select y textarea cuando el usuario cambia el valor desplegado del elemento y después mueve el foco hacia otro elemento.
    onload El evento onload sólo se puede asociar a body y es lanzado cuando el documento y su contenido externo, incluyendo imágenes, han sido completamente cargados.
    Eventos intrínsecos de uso común en JavaScript

    Supóngase que en una ventana del navegador el documento actual es reemplazado por otro, por ejemplo, cuando el usuario escribe un nuevo URL. El nuevo documento no puede acceder a las propiedades que el documento previo creó en la ventana, ya que el objeto window es reestablecido (reset) por el navegador. Esto implica que todas las funciones y propiedades que los scripts definan, durarán mientras el documento actual se mantenga activo.

    Consideraciones de seguridad

    El hecho de que código ajeno sea ejecutado en su máquina a través de un navegador, da oportunidad a que intenciones malignas puedan llevarse a cabo. Por esto, los navegadores simplemente no soportan ciertas funcionalidades que en otros lenguajes son naturales, como la capacidad de leer, escribir o eliminar archivos en la computadora cliente.

    Otras funcionalidades están limitadas. Por ejemplo, JavaScript puede emplear el protocolo HTTP para intercambiar información con el servidor pero no puede abrir un socket o utilizar alguna primitiva de programación de red. Algunas de estas restricciones son controlables por el usuario, ajustando la política de seguridad del navegador. De acuerdo a esta configuración su programa JavaScript:

    • Podría abrir nuevas ventanas pero sólo en respuesta a un evento del usuario (como onclik).
    • Podría cerrar ventanas, pero sólo las abiertas por sí mismo.
    • No puede ocultar el texto en la barra de estado cuando el cursor se mueve sobre un enlace.
    • No puede crear una ventana de área pequeña o muy grande, sin barra de título ni estado.
    • No puede leer ni modificar documentos cargados de servidores diferentes (same-origin policy).

    La política del mismo origen (same-origin policy) indica que un script puede acceder únicamente a contenido que tiene el mismo origen que el documento que contiene el script. Es decir, que su código no puede acceder a otro documento que tenga cargado su navegador en otra ventana obtenido de otro sitio web. También dicta que el código JavaScript puede comunicarse a través del objeto XMLHttpRequest sólo con el servidor web de donde se obtuvo el documento.

    Temporizadores y animaciones

    El objeto global window provee varios métodos y otras propiedades para manipular el navegador, ventanas, direcciones, el historial y similares.

    El método window.setTimeout(code, delay) ejecuta el código JavaScript enviado en el parámetro code, delay milisegundos después de que se hace la invocación. Retorna un identificador opaco que necesitará el programador si desea cancelar dicho temporizador con el método window.clearTimeout(). El código es invocado sólo una vez. Si se quiere que ocurra repetitivamente, el código en code debe establecer otro setTimeout() o bien usar el método setInterval(). El método timer = window.setInterval(code, period) ejecuta el código code repetitivamente en intervalos de period milisegundos, hasta que se invoque window.clearInterval(timer). Los temporizadores son muy útiles para realizar animaciones, como el siguiente reloj digital.

    
    
       Digital clock
       
    
    
    
       
    HH:MM:SS
    ]]>
    Un reloj digital animado con JavaScript. Correr este ejemplo.

    En el documento del js_clock_animation, el elemento con identificador clock de la línea 11 será utilizado para desplegar la hora local del navegador. Cuando el navegador carga el cuerpo de este documento, mostrará el div como de costumbre, aplicándole los estilos que se declararon en la parte superior. Luego encontrará un elemento script y lo ejecutará como es sabido. La invocación a setInterval() en la línea 14 le indica al navegador que debe ejecutar el código updateClock() dentro de 1 segundo, cada segundo. Al ser invocada, la función updateClock() debe cambiar el contenido del <div id="clock">...</div> con el valor actual de la hora. JavaScript requiere una referencia al objeto div que tiene el identificador clock, y la consigue invocando el método document.getElementById() que se estudiará luego. Una vez obtenida la referencia al elemento div, se cambia su contenido con la hora actual en el navegador obtenida en forma de string.

    5 pts.

    Modifique el ejemplo del reloj digital para que muestre los milisegundos (separados por un punto de los segundos), y se actualice al menos cuatro veces cada segundo.

    El js_text_animation muestra un texto moverse de izquierda a derecha, en un ancho de 320 pixeles. Esta vez no se modifica el contenido de un elemento particular, sino su posición, lo cual es responsabilidad de la presentación, por lo que el código JavaScript debe modificar dinámicamente el estilo CSS del elemento con identificador text (línea 12). El estilo de un elemento se accede en JavaScript a través de su propiedad style, la cual es un objeto cuyas propiedades tienen el mismo nombre que las propiedades CSS en notación "camelCase" (margin, marginTop, etc.), y sus valores son siempre un string. En js_text_animation, cada vez que se invoca, animateText() calcula en la variable global textLeft la nueva posición del texto (líneas 19 y 20); y en la línea 22 asigna el resultado de este cálculo a la propiedad style.left, cuyo efecto es el mismo a haber escrito #text { left: <textLeft>px; } en CSS. Para que esto funcione, el elemento #text debe "flotar" sobre el documento, lo cual se hizo en la línea 7 indicando que su posición es absoluta.

    
    
       
       Texto animado
       
    
    
    
       
    Su nombre aquí
    ]]>
    Un texto animado con JavaScript para desplazarse en vaivén de izquierda a derecha. Correr este ejemplo.
    5 pts.

    Modifique el ejemplo del texto animado para que cuando el usuario haga click en el texto, la animación se detenga, y si se vuelve a hacer click, la animación se reanude. Es obligatorio detener los temporizadores, de lo contrario, su aplicación estará mal empleando recursos de la máquina del cliente.

    Información del navegador, la ventana y la pantalla

    El objeto global window tiene varias propiedades de sólo lectura que informan el tamaño de la ventana, el tamaño del documento y la posición del navegador en el escritorio:

    Propiedad Descripción
    window.outerWidth, window.outerHeight Ancho y alto de la ventana del navegador.
    window.screenX, window.screenY Posición del navegador en el escritorio del usuario.
    window.innerWidth, window.innerHeight Tamaño del área donde el documento se despliega (también llamada área cliente o viewport. Equivale al tamaño de la ventana del navegador sin las barras de menú, herramientas, scrollbars, etc.
    window.pageXOffset, window.pageYOffset El segmento del documento actualmente desplegado en la ventana del navegador, expresado como la posición de las barras de desplazamiento (scrollbars).
    Propiedades de window para obtener la geometría del navegador
    5 pts.

    Modifique su solución del texto animado para que el texto no esté limitado a un ancho de 320 pixeles, sino que se ajuste dinámicamente al ancho del navegador.

    5 pts.

    En su solución del texto animado, reemplace el texto por una imagen, como una esfera o algún gráfico de su agrado. Haga que el gráfico se mueva tanto horizontal como verticalmente por el área de la ventana sin salirse de esta. Es decir, que el gráfico siempre es visible aún cuando se acerque a los extremos de la ventana y aunque la ventana del navegador sea redimensionada.

    El objeto window.screen provee información sobre la pantalla del usuario, por ejemplo: las dimensiones en pixeles del escritorio (screen.width y screen.height), la profundidad de color en bits por píxel (screen.pixelDepth), el área usable del escritorio sin incluir la barra de tareas (screen.availWidth y screen.availHeight). Con estas propiedades el programador puede escoger qué imágenes presentar, centrar una ventana en el escritorio o tareas similares.

    El objeto window.navigator contiene información sobre el navegador mismo, como su nombre (navigator.appName), versión (navigator.appVersion), el nombre codificado (navigator.appCodeName, el sistema operativo para el que se compiló el navegador (navigator.platform), si tiene habilitados los cookies (navigator.cookieEnabled), y la identificación que el browser envía en sus encabezados HTTP (navigator.userAgent). No es recomendable utilizar esta información para escribir funcionalidad dependiente del navegador, sino para propósitos de estadísticas o bitácoras.

    5 pts.

    Escriba un programa JavaScript que genere una o varias tablas con la información del navegador, la ventana y la pantalla citada anteriormente. No utilice document.write(), sino que su programa debe llenar un elemento section del documento (puede utilizar su propiedad innerHTML). Provea un botón "Actualizar" que cada vez que se presiona, refresca la información anterior. Recuerde aprovechar el operador for-in.

    Abrir y manipular ventanas

    JavaScript permite al autor crear nuevas ventanas de navegador en las que puede cargar documentos existentes de su servidor web o generar un nuevo documento dinámicamente. Sin embargo, el abuso que se ha cometido por publicidad y otros fines, ha obligado a los fabricantes de navegadores a restringir esta funcionalidad de acuerdo a la política de seguridad, por ejemplo, a permitir abrir ventanas sólo en respuesta a un evento del usuario.

    Una invocación al método window.open(url, name, features, replaceHistory) crea y retorna una referencia hacia una nueva ventana, y por ende, un nuevo objeto window con toda su descendencia de objetos. La nueva ventana cargará un documento si se especifica un url en el primer parámetro, de lo contrario, tendrá un documento vacío. El parámetro name le da un nombre a la ventana, si ya existe una con ese nombre simplemente se reutiliza, y en tal caso, si replaceHistory es true el historial de navegación en esa ventana es reemplazado; si es false o se omite, el nuevo documento es simplemente agregado al historial (y por tanto, el usuario podría presionar el botón "atrás" para retonar a documentos cargados previamente).

    El siguiente ejemplo crea una pequeña ventana emergente de ayuda cuando se presiona el botón, y la cierra cuando se vuelve a presionar el botón. Las ventanas se cierran con el método window.close() que cierra gráficamente la ventana pero no destruye su correspondiente objeto window.

    Ayuda
    
    ]]>
    Abrir una ventana en JavaScript. Correr este ejemplo.

    El tercer parámetro, features, de window.open() permite especificar el tamaño de la nueva ventana y otras decoraciones gráficas. Si se omite, se le dará tamaño estándar y todas las decoraciones existentes (barra de menú, barra de estado, ...). Algunas combinaciones son restringidas por razones de seguridad, por ejemplo, una ventana muy pequeña o situada en una zona no visible.

    El objeto retornado por window.open() se puede manipular como cualquier otro objeto window. El ejemplo del js_open_window_document_write, genera un documento dinámicamente en una nueva ventana, utilizando su respectivo método document.write().

    Hello world!");   // Output document content
    subdoc.close();                          // End the document
    ]]>
    Crear contenido en el documento de una ventana emergente

    Nótese que tanto document como window tinen métodos open() y close(). El método document.open(url) carga un documento a partir del url o genera uno vacío si se omite url. Invocar a document.write() es seguro en una ventana nueva ya que el documento se está cargando (parsing). El método document.close() indica al navegador que el documento ha terminado de cargarse (parsing), el cual responde deteniendo la animación de carga. Si nunca se llama a document.close(), el navegador creerá que está ante un documento incompleto.

    10 pts.

    Modifique el ejemplo de la ventana de ayuda. Cuando se presiona el botón, cree una nueva ventana con un documento vacío, es decir, el parámetro url de window.open() debe estar vacío. Haga que su programa JavaScript cree el contenido del documento dinámicamente en la nueva ventana. El contenido debe ser el mismo del window_dump, es decir, las propiedades y los valores del objeto window que contiene el script. Puede utilizar subwindow.document.write() o la propiedad subwindow.document.innerHTML.

    El objeto window tiene métodos para mover y redimensionar la ventana. Deben usarse con mucha cautela sólo en situaciones que realmente provean una mejor experiencia del usuario. De lo contrario es una pobre práctica, ya que la geometría y posición de la ventana debe ser un privilegio del usuario. Son los siguientes: window.moveTo(x, y) mueve la esquina superior izquierda a las coordenadas dadas; window.moveBy(despX, despY) mueve la ventana tantos pixeles relativos a la posición actual; window.resizeTo(width,height) y window.resizeBy(addToWidth, addToHeight) cambian el tamaño de la ventana.

    El método window.focus() hace que la ventana sea la activa, y window.blur() hace que renuncie a serlo. Es común llamar a focus() después de hacer un window.open(), ya que las ventanas recién creadas no lo tienen por defecto.

    Es común querer abrir un documento existente en una nueva ventana y luego hacer que ésta se desplace a diferentes fragmentos del documento dinámicamente. Si los fragmentos están identificados con el atributo id (como en <div id="frag1">...</div>) o con anclas (<a name="frag2">...</a>), se puede cambiar la ubicación del documento con un una de las siguientes instrucciones:

    var subwindow = window.open('help.html', 'help_window');
    subwindow.location.hash = "#frag1";    // crea una entrada en el History de subwindow
    subwindow.location.replace("#frag1");  // no crea una entrada en el History de subwindow
    

    Ubicación del documento

    La propiedad window.location de una ventana representa el URL del documento que está desplegado en dicha ventana. Es un objeto que tiene las siguientes propiedades:

    Propiedad Descripción
    href Es un string con el texto completo del URL.
    protocol, host, pathname, search Representan partes individuales del URL.
    reload() Recarga la página como si el usuario lo hiciera en el navegador.
    replace(url) Reemplaza el documento actual en la ventana por uno nuevo cuyo URL es dado por parámetro. No genera una entrada en el historial de la ventana, de modo que el usuario no tiene forma de regresar al documento previo.
    Propiedades del objeto window.location

    Al objeto mismo window.location se le puede asignar un string, de la forma window.location = url, que causa el mismo efecto que llamar su método window.location.replace(url), con la diferencia de que se agrega una entrada al historial de navegación de la ventana, de tal forma que el usuario puede retornar al documento previo.

    Cuadros de diálogo

    El objeto window provee tres métodos para desplegar cuadros de diálogo. window.alert(msg) despliega un mensaje y espera que el usuario lo acepte. window.confirm(msg) presenta un mensaje y solicita al usuario que decida si lo acepta o cancela, lo cual se retorna como un boolean. window.prompt(msg, defaultValue) presenta el mensaje msg y espera que el usuario ingrese un string el cual es retornado o null si cancela.

    Deben usarse con moderación, o mejor aún, nunca. La mayoría de usuarios se sentirá molesta al experimentarlos y recuerde que ellos tienen el poder forzar el navegador a cerrarse, deshabilitarle JavaScript o nunca volver a su sitio. Así que estos métodos son de ligera utilidad para el programador durante el proceso de desarrollo. Hace varios años, el navegador reportaba errores de JavaScript utilizando diálogos, lo cual era impertinente: le reclamaba al visitante errores que no eran de él. Los navegadores han cambiado a ocultar los errores y el programador debe buscarlos en alguna bitácora, consola o similar.

    El objeto document

    En esencia un navegador es un programa que despliega un documento web en una ventana. La sección anterior explica cómo manipular con JavaScript esa ventana. Esta sección explica cómo manipular dinámicamente el documento cargado en ella.

    Hasta el momento las propiedades más utilizadas del objeto document en este material han sido los métodos write() y writeln(). Ambos reciben una cantidad arbitraria de parámetros y los escriben en el documento para que sean analizados (parsed) por el navegador posteriormente. Por eso, estos métodos sólo se deben invocar mientras se está cargando (parsing) el documento HTML y no XHTML, ya que XML prohíbe este comportamiento. Como es de esperar, writeln() después de imprimir todos sus parámetros, agrega un carácter de cambio de línea. Otras propiedades útiles del objeto document son presentadas en la js_window_document, y con ellas se escribe, a modo de ejemplo, un pie de página dinámico en el js_dynamic_footer.

    Propiedad Descripción
    document.title Accede al título del documento que se encuentra en el encabezado del mismo.
    document.lastModified Contiene un string con la fecha de última modificación del documento.
    document.URL Es un string con el URL completo de donde se obtuvo el documento.
    document.referrer Es un string con el URL del recurso a través del cual el usuario llegó al documento actual.
    document.domain Indica el dominio al cual pertenece el documento, y es usado por la política del mismo origen (same origin policy).
    Propiedades del objeto window.document

    El modelo de objetos del documento (DOM)

    Cuando el navegador carga un documento (X)HTML crea un objeto JavaScript por cada elemento, comentario, o trozo de texto que encuentra en el archivo. Estos objetos se asocian entre sí en una jerarquía llamada modelo de objetos del documento (DOM: Document Object Model), la cual es accesible y modificable a través de JavaScript. Es decir, el DOM es una representación interna del documento utilizando objetos. Un cambio en el DOM se refleja de inmediato en el navegador, lo que permite al autor ajustar el documento dinámicamente para mejorar la comunicación con sus lectores. Es quizá la funcionalidad más importante que un autor busca de JavaScript.

    Los objetos en la jerarquía del DOM reciben el nombre genérico de nodos, construidos con la pseudoclase Node. El nodo raíz es siempre el documento, el cual contiene nodos opcionales (declaración XML, declaración de tipo de documento, comentarios) y el nodo del elemento html, llamado elemento documento (document element). Este último tiene dos hijos: el nodo del encabezado (head) y el nodo del cuerpo del documento (body). Los hijos del nodo body varían de acuerdo al documento. Por ejemplo, la fig_node_tree muestra un documento sencillo y el árbol de nodos que el navegador genera a partir de él.

    Un documento y su árbol de nodos

    La pseudoclase Node

    Las relaciones jerárquicas entre nodos implican que un nodo puede tener cero o más nodos hijos (child nodes), nodos hermanos (siblings), un nodo padre (parent), nodos descendientes y nodos ancestros. Estas relaciones se implementan como propiedades de la pseudoclase Node. Dado un nodo se puede acceder a los otros nodos con los que está relacionado. Estas y otras propiedades se resumen en la siguiente tabla.

    Propiedad Descripción
    Node.childNodes[] Un arreglo que contiene los hijos del nodo actual en el mismo orden en que fueron definidos en el documento. Si el nodo actual no tiene hijos, este arreglo estará vacío.
    Node.firstChild El primer nodo hijo del nodo actual, o null si no tiene hijos.
    Node.lastChild El último nodo hijo del nodo actual, o null si no tiene hijos.
    Node.nextSibling El nodo hermano que continúa al actual o null si es el último hijo del nodo padre (parentNode). Equivale al nodo que sigue al actual en el arreglo parentNode.childNodes[].
    Node.previousSibling El nodo hermano que precede al actual o null si es el primer hijo del nodo padre (parentNode). Equivale al nodo que precede al actual en el arreglo parentNode.childNodes[].
    Node.parentNode El nodo padre o contenedor del nodo actual. Es null en el caso del nodo raíz, nodos que han sido separados (removidos) del documento, o nodos creados libremente que aún no han sido insertados en el documento.
    Node.nodeType Un entero que indica el tipo de nodo, por ejemplo: elemento (1), texto (3), comentarios (8). Ver xml_dom_node_types.
    Node.nodeName Un string con un posible nombre para el nodo. Si el nodo es un elemento se utiliza el nombre del elemento ("body", "div", "p", etc.). Para los demás tipos de nodos se utiliza un texto generado de concatenar el símbolo de número con el tipo de nodo, por ejemplo "#text", "#comment", "#document", etc.
    Node.nodeValue Si el nodo es de texto (nodeType == 3) o comentario (nodeType == 8), esta propiedad tendrá un string con dicho texto; de lo contrario el valor null.
    Node.textContent Contiene el texto si el nodo es de texto (nodeType == 3) o comentario (nodeType == 8), en la misma forma que nodeValue. Para un elemento (nodeType == 1) contiene el texto resultado de concatenar todos los nodos de texto descendientes.
    Node.ownerDocument Una referencia hacia el documento que contiene este nodo. Sirve, por ejemplo, para saber si dos nodos son parte del mismo documento.
    Propiedades de la pseudoclase Node del XML DOM

    El código del js_print_nodes recorre recursivamente todos los nodos del documento e imprime algunas de las propiedades heredadas de la pseudoclase Node. La cantidad de nodos está fuertemente influenciada por el espacio en blanco que se utilice para indentar el marcado, ya que el parser lo interpretará como datos de carácter y los almacenará en nodos de texto. [Para este ejemplo, la impresión con document.write() debe hacerse en un documento distinto, ya que si se hace sobre el mismo, generará una recursión infinita].

    Una función recursiva que recorre el árbol de nodos del documento e imprime propiedades heredadas de la pseudoclase Node. Correr ejemplo completo sin espacios en blanco, con indentación en XHTML, o con indentación en HTML.

    El ejemplo del js_print_nodes permite observar que los navegadores agregan a la jerarquía nodos #text por el texto en blanco que aparece entre los elementos del documento, debidos a la indentación del autor. Además los nombres de los elementos en XHTML se mantienen en minúsculas mientras que en HTML son convertidos a mayúsculas.

    Además de las propiedades para acceder a nodos relacionados de la xml_dom_node_properties, la pseudoclase Node provee métodos para modificarlos, los cuales se listan en la xml_dom_node_methods.

    Propiedad Descripción
    Node.appendChild(newChild) Agrega el nodo newChild al final del arreglo childNodes[]. El cambio se ve reflejado de inmediato en el documento cargado en el navegador. Si newChild ya forma parte del documento, será removido de su posición actual y reinsertado en la nueva posición.
    Node.insertBefore(newChild, referenceChild) Inserta el nodo newChild en el arreglo childNodes[] justo antes que el nodo referenceChild, el cual obligatoriamente debe existir y ser hijo del nodo al cual se le invocó este método. Si referenceChild es null, newChild se insertará al final. Si newChild ya es parte del documento, será removido de su posición actual y reinsertado en la nueva posición.
    Node.replaceChild(newChild, oldChild) Reemplaza oldChild con newChild. Si newChild ya es parte del documento, será removido de su posición actual y reinsertado en la nueva posición. oldChild es separado del documento y el cambio se refleja en el navegador. El objeto oldChild no es eliminado de la memoria, sino que sigue vigente y puede ser reinsertado en el documento posteriormente.
    Node.removeChild(child) Quita al nodo child del arreglo childNodes[] y del documento (el cambio se refleja visualmente en el navegador). El objeto nodo child no es eliminado de la memoria, y puede ser reinsertado en el documento posteriormente.
    Node.cloneNode(recursively) Retorna una copia del nodo al cual este método es invocado. No clona los hijos y descendientes del nodo a menos que se envíe true en el parámetro recursively. El nodo retornado no es parte del documento, por lo que debe ser insertado posteriormente si se quiere que sea visible al lector.
    Node.isEqualNode(other) Retorna true si el nodo es idéntico al enviado por parámetro, es decir, tienen los mismos valores para sus propiedades de datos (como el nombre y tipo), y así recursivamente para todos sus hijos.
    Métodos de la pseudoclase Node del XML DOM

    Los métodos de la xml_dom_node_methods permiten mover nodos existentes de un lugar a otro, o clonarlos. El siguiente ejemplo ordena los nodos existentes de una lista alfabéticamente.

    
        

    Reubicar nodos en el documento

    1. Los
    2. 12
    3. elementos
    4. de
    5. esta
    6. lista
    7. serán
    8. ordenados
    9. alfabéticamente
    10. sin contar
    11. Mayúsculas
    12. Incluyendo este párrafo.

    ]]>
    Reubicar nodos en el documento. Correr este ejemplo.

    Nótese que en el ejemplo anterior se construyó un arreglo temporal (llamado elements[]), el cual se llenará únicamente con los elementos que deben ser ordenados, y luego serán reinsertados en el documento. ¿Por qué no se hizo este cambio directamente en list_element.childNodes[]? Hay varias razones. La más importante es porque childNodes[] no es realmente un arreglo, sino un objeto que se comporta como tal llamado objeto tipo arreglo (array-like objects), y su propósito es proveer un arreglo controlado, casi de sólo lectura. Por ejemplo, el programador no puede invocar a list_element.childNodes.sort() porque el objeto tipo arreglo no implementa este método.

    La segunda razón es que el arreglo list_element.childNodes[] muy probablemente contiene otros hijos que no son de importancia ordenar, como nodos de texto (surgidos de los espacios en blanco usados para indentar el código fuente) o comentarios. Por esto, es una práctica común construir un nuevo arreglo temporal escogiendo los nodos que realmente se quieren modificar, afectar al arreglo temporal, y cuando el procesamiento esté listo, actualizar el documento. Esto reduce además un desagradable efecto de parpadeo (flickering) que confunde al lector al ver partes del documento cambiar arbitrariamente.

    5 pts.

    Modifique el ejemplo de ordenar elementos de la lista (js_sort_list) para que cuando se presiona el botón, se alterne el orden de los elementos entre ascendente y descendente en la lista.

    Creación de nodos en el documento

    Cuando se debe crear un nuevo nodo en el documento, no se debe hacer con el operador new, de la forma new Node(), sino utilizar los métodos document.createXxx(data) de la pseudoclase Document, como los listados en la js_document_create_node_methods. Todos ellos crean un nuevo nodo el cual está asociado al documento, pero no es visible. Cuando el programador haya terminado de procesarlo (por ejemplo, inicializarlo), deberá insertarlo en la jerarquía de nodos del documento en el punto que quiere que sea visible al lector, usando alguno de los métodos de la pseudoclase Node como appendChild(), insertBefore() o replaceChild() listados en la xml_dom_node_methods. El ejemplo del js_append_child_node inserta nodos dinámicamente en una lista ordenada.

    Método Descripción
    document.createElement(name) Crea un nodo elemento del nombre dado. Si el elemento tiene texto en el contenido, se debe crear al menos un nodo de texto con createTextNode() y agregarlo como hijo.
    document.createTextNode(text) Crea un nodo de texto con el texto dado por parámetro.
    document.createComment(text) Crea un nodo comentario con el texto dado por parámetro.
    att = document.createAttribute(name) Crea un nodo atributo con el nombre dado y lo retorna. El valor del atributo se puede asignar luego con att.value = 'valor';. El atributo se puede aplicar a uno o más elementos con el método elemento.setAttributeNode(att).
    document.createCDATASection(text) Crea una sección CDATA con el texto dado por parámetro. Sólo está disponible en XML DOM, es decir, en jerarquías de objetos generadas a partir de documentos XHTML y no HTML.
    Algunos métodos de Document para crear nodos
    
        

    Crear e insertar nodos en el documento

    1. Presione el botón para agregarle elementos a la lista
    ]]>
    Crear e insertar nodos en el documento. Correr este ejemplo.

    La línea 11 del js_append_child_node crea un objeto nodo en el documento, pero que no se ha indicado en qué punto del documento debe aparecer, por lo que no es visible en la ventana del navegador. Esto ocurre hasta cuando el nuevo nodo es insertado en la jerarquía de nodos del documento (DOM), en este caso en la línea 14 como el último nodo hijo de la lista con identificador dynamic_list declarada entre las líneas 4 a 6.

    Cada vez que el usuario presiona el botón en el js_append_child_node se construye un elemento li vacío. Para especificar el texto que va en su contenido hay dos formas: con la propiedad innerHTML o creando un nodo de texto (línea 12) y agregarlo como hijo del recién creado li, como se hizo en la línea 13 del js_append_child_node. La propiedad innerHTML sólo está disponible en HTML, mientras que crear un nodo y agregarlo al documento (DOM) es el método universal.

    10 pts.

    Escriba un documento XHTML con un poema, y un botón que al ser presionado invierte el orden de las estrofas (no de los versos), utilizando los métodos de la pseudoclase Node. Imprima los números de las estrofas y resáltelos con estilos CSS para que el cambio sea visualmente evidente.

    XML DOM y HTML DOM

    Los nodos pueden ser de distinta naturaleza: elementos, atributos, comentarios, texto, etc. La propiedad Node.nodeType indica el tipo de un nodo particular; es un entero que puede tomar el valor de una de las siguientes constantes:

    Valor Constante Pseudoclase XML Pseudoclase HTML
    1 Node.ELEMENT_NODE Element HTMLElement
    2 Node.ATTRIBUTE_NODE Attr
    3 Node.TEXT_NODE Text
    4 Node.CDATA_SECTION_NODE CharacterData
    5 Node.ENTITY_REFERENCE_NODE EntityReference
    6 Node.ENTITY_NODE Entity
    7 Node.PROCESSING_INSTRUCTION_NODE --
    8 Node.COMMENT_NODE Comment
    9 Node.DOCUMENT_NODE Document
    10 Node.DOCUMENT_TYPE_NODE --
    11 Node.DOCUMENT_FRAGMENT_NODE DocumentFragment
    12 Node.NOTATION_NODE --
    Tipos de Node del XML DOM

    El js_element_count muestra una función que recorre recursivamente todos los nodos del documento contando cuántos de ellos son elementos. Sugerencia: verifique si el conteo es correcto: cuente los elementos manualmente en el código fuente que genera la página o al inspeccionar el resultado.

    
    
    
       
       Conteo de elementos
       
    
    
    
       

    Conteo de elementos

    El número de elementos presentes en este documento es:

    ]]>
    Una función recursiva que recorre el árbol de nodos del documento y retorna cuántos de ellos son de tipo elemento. Correr este ejemplo.
    10 pts.

    Escriba en un archivo .js, una función que recorre el documento en que fue invocada y retorna un string con el texto de todos los comentarios. Imprima este string en un elemento pre al final del documento. El elemento pre y su contenido debe crearlo desde JavaScript usando el DOM. Puede descargar una página que guste de la web que tenga comentarios y alterarla para incluir su script al final del cuerpo.

    15 pts.

    Escriba una función en un archivo doc_statistics.js que al ser invocada crea un nuevo documento en una ventana emergente con estadísticas del documento donde se invocó la función. El contenido de la ventana emergente es una tabla (X)HTML con las columnas: número de línea (#), el nombre del elemento (Elemento), la cantidad de veces en que aparece en el documento original (Ocurrencias), y el porcentaje de ocurrencia de dicho elemento en el documento (Porcentaje). En las filas de la tabla debe aparecer cada uno de los distintos elementos que conforman el documento, como se ve abajo. Al final agregre como pie de tabla una fila con los totales. Descargue de la web una página de su interés y modifíquela para ejecutar su script al final del documento. Note que su función sólo debe considerar elementos y no nodos de otro tipo.

    #ElementoOcurrenciasPorcentaje
    1html10.1%
    2head10.1%
    ............
    45img9510%
    Total581100%

    Por cada tipo de nodo hay una pseudoclase hija de Node, que aparece en la tercera columna de la xml_dom_node_types. Por ejemplo, cuando el navegador carga el documento y encuentra un comentario, no construye un objeto Node puro, sino que construye un objeto de la pseudoclase Comment, la cual es hija de Node; y, de igual forma, cuando encuentra un párrafo creará un objeto Element que es también hijo de Node. Esta jerarquía de pseudoclases se ilustra la fig_node_inheritance.

    Herencia de pseudoclases del XML DOM y HTML DOM

    Cada subclase agrega propiedades a la pseudoclase Node. Por ejemplo, la pseudoclase Element define las siguientes propiedades útiles:

    Propiedad Descripción
    Element.tagName String con el nombre del elemento, por ejemplo: "body", "p", etc. Equivale a Node.nodeName.
    Element.attributes[] Accede a los atributos del elemento en el orden en que fueron definidos.
    Element.getAttribute(name) Retorna el valor del atributo name como un string, o null si el elemento no tiene este atributo.
    Element.setAttribute(name, value) Asigna el string value al atributo con nombre name del elemento. Si el atributo no existe, lo crea.
    Element.removeAttribute(name) Elimina el atributo con nombre name del elemento. No produce ningún error si el atributo no existe.
    Element.getAttributeNode(name) Retorna un objeto de tipo Attr que permite por ejemplo saber si el atributo fue definido o se está usando su valor por defecto.
    Element.id El valor del atributo id="value", si fue definido para este elemento.
    Element.className El valor del atributo class="value", si fue definido para este elemento.
    Element.children[] Un arreglo que contiene únicamente los elementos hijos de este elemento, en lugar de todos los nodos como ocurre con el arreglo childNodes heredado de Node. Quizá childElements hubiese sido un nombre más apropiado.
    Element.childElementCount La cantidad de elementos hijos. Equivale a children.length. Nótese que no es la cantidad de nodos hijos.
    Element.innerHTML Un string que con el marcado HTML o XML que representa el contenido del elemento. Si se asigna otro string, será "parseado" por el navegador, el resultado reemplazará a los nodos hijos del elemento, y el efecto será inmediatamente visible en el documento.
    Element.outerHTML Un string que con el marcado HTML o XML que representa el elemento mismo más su contenido. Si se asigna otro string, será "parseado" por el navegador, el resultado reemplazará al elemento y sus nodos hijos. El efecto será inmediatamente visible en el documento.
    Element.style Un objeto CSSStyleDeclaration con los estilos definidos en el documento para este elemento. Se puede modificar dinámicamente. No contiene los estilos computados.
    Propiedades de Element en el XML DOM

    El objeto Attr representa un atributo de un elemento particular, aunque casi nunca se utiliza, ya que el objeto Element tiene propiedades y métodos para manipular sus atributos. Quizá su propiedad más útil es Attr.specified que permite determinar si el valor del atributo fue explícitamente escrito en el documento, sino se está tomando el valor por omisión.

    Los navegadores realmente implementan dos modelos de objetos del documento (DOM), uno para XML y otro especializado para HTML (fig_node_inheritance). Dado que JavaScript utiliza XML para transferir datos entre el servidor y el cliente, requiere poder manipular estos documentos a través de una jerarquía de objetos. El DOM que se ha presentado hasta el momento se llama XML DOM, compuesto de objetos bastante genéricos como lo es también XML.

    Sin embargo, el navegador provee un conjunto de pseudoclases especializadas para HTML, que componen lo que se llama HTML DOM y que heredan de las pseudoclases presentes en el XML DOM. Algunas de estas pseudoclases se presentan en verde en la fig_node_inheritance. El principal distintivo del HTML DOM es que define la pseudoclase HTMLElement para todos los elementos que sólo tienen los atributos comunes (em, span, dt, etc.) y una pseudoclase HTMLXxxElement para cada elemento Xxx que tiene atributos propios, como HTMLDocument, body (HTMLBodyElement), p (HTMLParagraphElement), ul (HTMLUListElement), etc.

    Las pseudoclases HTMLXxxElement definen propiedades homónimas a los atributos (X)HTML que son de lectura y escritura. Por ejemplo HTMLImageElement define la propiedad string src que puede cambiarse dinámicamente con JavaScript y su efecto es inmediato en el navegador. Los nombres son homónimos a XHTML, en minúsculas, excepto el atributo class="" que en JavaScript se renombra className debido a que class es una palabra reservada. El tipo de datos de cada atributo es el más adecuado, por ejemplo, HTMLImageElement.src es un string, HTMLImageElement.width es un entero y HTMLBodyElement.onload es una función de JavaScript.

    El autor puede utilizar estos atributos definidos por las pseudoclases HTMLXxxElement directamente con el operador punto o el operador corchetes, si está seguro de que el objeto es del tipo xxx adecuado. También puede emplear los métodos getAttribute(name) y setAttributeValue(name, value) heredados de Element en el XML DOM; que a diferencia de los atributos de HTMLXxxElement, sólo retornan y reciben valores string.

    5 pts. Reimplemente el ejercicio 5.22 (documento aleatorio) usando la jerarquía de Node, en lugar de usar una jerarquía de clases propias. Provea una función que al ser invocada obtiene una referencia al elemento body y construye un documento aleatorio.

    Localizar elementos en el documento

    De todos los tipos de nodos el elemento es incuestionablemente el más importante para el autor, tanto que el objeto Document del XML DOM y HTMLDocument del HTML DOM, proveen varios métodos útiles para localizar elementos por algún criterio. Estos se resumen en la siguiente tabla.

    Método Descripción
    document.getElementById(id) Localiza el único elemento que tiene el identificador id en su atributo homónimo. Retorna el objeto HTMLElement que tiene este identificador o null si ningún elemento en el documento está identificado con el string id.
    document.getElementsByTagName(tagName), element.getElementsByTagName(tagName) Selecciona todos los elementos en el documento que fueron creados con la etiqueta tagName, y los retorna en un objeto tipo arreglo que tiene el mismo orden en que aparecen en el documento. Por ejemplo, document.getElementsByTagName('table') retorna un objeto tipo arreglo con todas las tablas del documento. La búsqueda se hace sin importar mayúsculas y minúsculas por compatibilidad con HTML, y si se envía un asterisco '*' en tagName retorna todos los elementos del documento.
    document.getElementsByClassName(classValue), element.getElementsByClassName(classValue) El atributo class="c1 c2 ... cN" indica que el elemento pertenece a una o más clases separadas por espacios (y no por comas). Una clase es una agrupación de elementos que comparten características comunes; por ejemplo, una clase ejercicio podría usarse para distinguir todos los párrafos que representen ejercicios en un libro (<p class="ejercicio">...</p>) y aplicarles estilos diferenciados. En JavaScript se puede tener un objeto tipo arreglo con todos los elementos del documento que pertenecen a una o a varias clases con el método document.getElementsByClassName(), que recibe un string con la lista de clases separadas por espacios sin importar el orden.
    document.querySelectorAll(selector), element.querySelectorAll(selector) CSS tiene una notación estándar para seleccionar elementos a los cuales aplicarles reglas de estilo; por ejemplo, el selector ".ejemplo" recupera todos los elementos que tienen el atributo class="ejemplo"; el selector "#cap01 a[target='blank']" selecciona a todos los enlaces que tienen el atributo <a target="_blank"> y que son descendientes del elemento identificado con id="cap01". En JavaScript el método document.querySelectorAll(selector) retorna un objeto tipo arreglo con todos los elementos que satisfacen el selector enviado por parámetro, el cual sigue la misma notación de los selectores de CSS.
    document.querySelector(selector), element.querySelector(selector) Hace lo mismo que querySelectorAll(), pero sólo regresa el primer elemento que satisface el selector en lugar de una lista de elementos.
    document.getElementsByName(name) El atributo name sirve para identificar varios objetos relacionados, especialmente una familia de botones de radio (radio buttons). Ya que varios elementos pueden tener el mismo nombre, este método retorna un objeto tipo arreglo de elementos que comparten dicho nombre. A diferencia de los demás, éste método sólo está disponible en HTML DOM y no en XHTML DOM.
    Métodos de HTMLDocument para localizar elementos

    Si los métodos de la htmldocument_search_element se invocan con el objeto document, buscarán elementos en el documento completo, pero a veces, es útil buscarlos sólo en un trozo del documento. La pseudoclase Element también define sus propias versiones de dichos métodos (a excepción de getElementById() y getElementsByName()), y hacen lo mismo que sus contrapartes de Document, con la diferencia de que en lugar de buscar en todo el documento, buscan únicamente en el subárbol del elemento al cual el método es invocado.

    Por conveniencia la pseudoclase HTMLDocument define las propiedades document.head, document.body y document.documentElement, que hacen referencia a sus respectivos elementos, lo cual ahorra al programador el tener que localizarlos con las funciones de búsqueda del documento:

    document.head == document.getElementsByTagName('head')[0];
    document.body == document.getElementsByTagName('body')[0];
    document.documentElement == document.getElementsByTagName('html')[0];
    

    Ejemplo: Preguntas frecuentes

    El ejemplo del js_faq_example_xhtml muestra una sencilla sección de "Preguntas frecuentes". Inicialmente se presentan sólo las preguntas y no las respuestas, lo que permite al visitante recorrerlas rápidamente. Una vez que encuentre la pregunta que le intriga, puede hacer clic en ella para desplegar su respuesta.

    Este ejemplo sirve para ilustrar varios conceptos comunes de la programación en JavaScript. De acuerdo a la filosofía Unobtrusive JavaScript, el uso de este lenguaje debería ser un aditamento opcional que mejora la comunicación con el usuario. En este caso, si el visitante tiene desactivado el intérprete de JavaScript en su navegador, podrá acceder a la sección de "Preguntas frecuentes" completa. Es decir, JavaScript no debe ser un requisito indispensable para que un documento web sea funcional; pero si está disponible, JavaScript sólo debería ser usado para mejorar la experiencia del usuario con el sitio web.

    El documento web no debe especificar comportamiento, sino que éste siempre debe estar en un archivo externo, el cual se liga con el atributo src del elemento script como se hizo en la línea 15 de faq.xhtml en el js_faq_example_xhtml. Si los scripts van a ejecutarse hasta después de que el documento haya sido cargado por completo, es buena práctica incluirlos hasta final del documento web. De esta forma el contenido se cargará tan rápido como sea posible, sin ser retrasado por código JavaScript que aún no va a correr.

    Al procesar la línea 15 de faq.xhtml en el js_faq_example_xhtml, el navegador deberá esperar a descargar el archivo faq.js completo. Cuando esto ocurre, encontrará que sólo tiene 1 instrucción ejecutable (línea 2), las demás sólo declaran funciones como propiedades del objeto window. La línea 2 es la única que el navegador ejecuta en esta etapa y básicamente le indica al navegador que debe invocar la función initFaq() inmediatamente después de que haya terminado de cargar el documento web por completo (esto se estudiará más adelante). El navegador registra el evento y continúa analizando (parsing) el resto del documento web faq.xhtml.

    Una vez que el navegador ha terminado de analizar el documento faq.xhtml, dispara el evento onload y ejecuta todos los manejadores que se hayan asociado a dicho evento. En este caso, la única función asociada es initFaq de las líneas 5 a 44, la cual se invocará con el fin de inicializar la lista de preguntas y respuestas. Inicializar esta lista significa ocultar las respuestas y hacer que los textos de las preguntas reaccionen al clic del ratón con el fin de mostrar u ocultar alternadamente dichas respuestas. Adicionalmente crea un par de botones: "Mostrar todo" para los visitantes que quieran leer o imprimir todas las preguntas, y el botón "Ocultar todo" para quienes cambien de opinión.

    
    
    1. ¿Texto de la pregunta 1?

      Respuesta de la pregunta 1.

    2. ¿Texto de la pregunta 2?

      Respuesta de la pregunta 2.

      Esta respuesta ocupa varios párrafos.

    Manejo de eventos del DOM level 2

    ]]>
    Un archivo .js que al ser incluido por un documento, agrega dos manejadores de eventos. Correr este ejemplo.

    El método Element.addEventListener() es parte de lo que se conoce como DOM Level 2, el cual establece que cuando un evento ocurre en un elemento, éste puede antenderlo o alguno de sus elementos padres, es decir, el evento se propaga por la jerarquía de elementos y puede ser atendido en una de las siguientes tres fases:

    • Capturing phase. El evento recorre desde el documento hasta el elemento esperando ser atendido. Es decir, un elemento padre del elemento que generó el evento puede atenderlo.
    • At target phase. El elemento que generó el evento tiene oportunidad de atenderlo.
    • Bubbling phase. El evento retorna desde el elemento hacia el documento.

    El tercer parámetro del método element.addEventListener(event, function, fase) controla la fase en la que será atendido del evento. Si es true se atenderá en la fase de captura, si es false en la fase objetivo o fase de ascenso (bubbling).

    Otra ventaja de usar addEventListener() en lugar de asignar manejadores de eventos directamente a los atributos intrínsecos (llamado DOM Level 0), es que una misma función puede menejar eventos generados en distintos lugares del documento. Por ejemplo, si quiere hacer algo cuando el cursor del ratón pase sobre cualquier párrafo del documento, en el DOM Level 0 tendría que recorrer todos los elementos p y asignarles la función manejadora; mientras que en el DOM Level 2, simplemente registra la función en el elemento document.body con addEventListener().

    Tanto en DOM Level 0 como DOM Level 1, la función que se asigna al atributo intrínseco o que se pasa en el segundo parámetro de element.addEventListener(event, function, fase) se convierte en una propiedad del elemento al cual se hizo la asignación o invocación. Es decir, esa función se convierte en un método del elemento. Cuando éste se invoca por el navegador, se hará como una invocación a un método normal del elemento, así la palabra reservada this hará referencia a dicho elemento, por lo que se puede usar dentro del código del manejador. El siguiente ejemplo muestra una mínima implementación de un juego de estallar una bolsa de burbujas. Nótese cómo la función popBubble es asignada a cada imagen de burbuja al evento onclick, lo que la convierte en un método, el cual utiliza el parámetro this para cambiar el origen de la imagen presionada por una burbuja estallada.

    
    
    
       
       Estallar burbujas