martes, 18 de enero de 2011

sábado, 6 de junio de 2009

Practica 4

En esta práctica he intentado hacer un xml que me sirva para, posteriormente usarlo como base de datos para una librería.

El xml empleado para hacer el dtd es el siguiente:



<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE biblioteca PUBLIC "Biblioteca/Filmoteca" "practica4.dtd">
<biblioteca>
<libro titulo="El señor de los anillos" autor="Tolkien" genero="Novela Fantastica">
<personaje nombre="Frodo Bolson">
Es un hobbit, hijo de Drogo Bolsón y Prímula Brandigamo y nacido el 22 de septiembre del año 2968 de la Tercera Edad del Sol. Llamado también "Portador del Anillo", Frodo fue el encargado de llevar el Anillo Único hasta el Monte del Destino para destruirlo.
</personaje>
<personaje nombre="Gandalf">
Es un espíritu Maia, uno de los Ainur menores, enviado a la Tierra Media durante la Tercera Edad del Sol para ayudar a sus habitantes en la lucha contra el Señor Oscuro Sauron. Allí adoptó el aspecto de un anciano de barba luenga y de color blanca grisácea, vestido con una gran capa gris, un sombrero puntiagudo de color azul y un gran cayado.
</personaje>

<personaje nombre="Aragorn">
Era capitán de los montaraces del norte, segundo de ese nombre, hijo de Arathorn II y de Gilraen, apodado Trancos en Bree, conocido como Thorongil (el "Aguila de la estrella") en Rohan y Gondor en los días de Thengel y Ecthelion II, de niño conocido en Rivendel como Estel ("Esperanza"), capitán de los Pueblos Libres durante la Guerra del Anillo y después, gobernante del Reino Unificado de Gondor y Arnor bajo el nombre de Elessar Telcontar.
</personaje>
<sinopsis>
La historia de El Señor de los Anillos se desarrolla en la Tercera Edad de la Tierra Media, un lugar ficticio poblado por Hombres y otras razas humanoides (Hobbits, Elfos y Enanos), así como por muchas otras criaturas reales y fantásticas. La novela cuenta el viaje del protagonista principal, el hobbit Frodo Bolsón, para destruir el Anillo Único y la consiguiente guerra que provocará el enemigo para recuperarlo, ya que es la principal fuente de poder de su creador, el Señor Oscuro Sauron.
</sinopsis>
</libro>
<libro titulo="La isla del tesoro" autor="Robert Louis Stevenson" genero="Novela Aventuras">
<personaje nombre="Jim Hawkins">
Es el joven que protagoniza la novela
</personaje>
<personaje nombre="Billy Bones">
Viejo marinero que se aloja en "El Almirante Benbow". En su cofre estaba el mapa del tesoro de Flint, por ello atrae a muchos piratas. Fiel consumidor de ron y grog, muere de un infarto en la taberna poco antes del asalto de los piratas.
</personaje>
<sinopsis>
Jim Hawkins es un adolescente que junto a sus padres trabaja en la posada del Almirante Benbow. Un día aparece un marinero con la mejilla cortada, cuya única posesión es un viejo cofre. La posada recibe la visita de un marinero ciego la misma noche que el padre de Jim muere. Éste amenaza a Bones diciéndole que más tarde él y sus esbirros le atacaran...
</sinopsis>
</libro>
<pelicula titulo="Underworld" fecha="2003">
<personaje nombre="Selene" actor="Kate Beckinsale">
Es una vampiro experta en el uso de muchas armas, medievales y modernas, especialmente el Walther P99 (pistola semi-automática). Se enamoró de Michael Corvin, el primer híbrido vampiro-licántropo.
</personaje>
<sinopsis>
Durante siglos, dos razas han ido evolucionan-do en lo más profundo del mundo de los huma-nos: los aristocráticos y sofisticados vampiros, y los brutales licántropos (hombres lobo). Para la humanidad, su existencia ha estado siem-pre dentro del universo mitológico. Sin embargo, estas razas de no-che son enemigos mortales la una de la otra, condenados a librar una guerra secreta hasta que sólo una de las dos quede en pie. En medio de este conflicto ancestral, una guerrera vampiro, Selene (Kate Beckinsale), descubre una conspiración de los licántropos para secuestrar a un joven doctor humano, Michael Corvin (Scott Speedman). Tras seguir a éste por toda la ciudad, entabla una in-sólita relación con él, y cuando los hombres se deciden a atacar, Selene se interpone entre las bestiales criaturas y el doctor. Mien-tras corre contra el tiempo intentando salvar a Michael y desmontar la trama urdida alrededor del humano por los licántropos, Selene descubre un secreto con terroríficas repercusiones para ambas tri-bus: un plan para desarrollar una nueva especie invencible que combina los poderes de ambos tipos de criaturas, carente a su vez de cualquiera de sus puntos débiles. Este hecho decantaría la ba-lanza a favor de los hombres lobo, quienes han llevado siempre las de perder en la guerra que llevan siglos librando.
</sinopsis>
</pelicula>
<pelicula titulo="El señor de la guerra" fecha="2005">
<personaje nombre="Yuri Orlov" actor="Nicolas Cage">
</personaje>
<sinopsis>
"El señor de la guerra" es una historia de aventuras y acción basada en un hecho real que supera a la ficción, situada en el mundo globalizado de la trata de armas. La película explora una consecuencia poco conocida del final de la Guerra Fría, la enorme cantidad de armas que de repente quedó disponible en los antiguos estados soviéticos para vender a los países en desarrollo (sobre todo de África), el negocio que significaba esto para los países desarrollados como Estados Unidos, China o la Unión Europea, y las inmensas sumas de dinero amasadas por los traficantes de armas que las encubrieron a éstos países que finaciaban guerras.

La película sigue las incansables aventuras del traficante de armas Yuri Orlov (Viktor Bout en la realidad), interpretado por Nicolas Cage y de su hermano Vitaly Orlov (Sergei Bout en la realidad) interpretado por Jared Leto . A través de algunas de las zonas de guerra más peligrosas, Yuri lucha por escapar de un implacable agente de la Interpol, de sus rivales en el negocio y hasta de alguno de sus clientes que incluyen a muchos de los más importantes dictadores. Finalmente, Yuri debe enfrentarse también a su propia conciencia.
</sinopsis>
</pelicula>
<pelicula titulo="El señor de la guerra" fecha="2005">
<personaje nombre="Randall 'Memphis' Raines" actor="Nicolas Cage">
</personaje>
<personaje nombre="Sara 'Sway' Wayland" actor="Angelina Jolie">
</personaje>
<sinopsis>
La película trata sobre un ex ladrón de coches llamado Randall "Memphis" Raines. Hace ya tiempo que Randall ha dejado atrás su pasado delictivo, pero recibe la visita de un amigo suyo que le informa sobre un hombre llamado Raymond Vincent Calitri, el cual ha raptado a su hermano y le amenazó con matarlo. Para salvar a su hermano menor, se ve obligado a hacer lo que mejor sabe: robar coches, tendrá que robar nada menos que 50 coches en una sola noche. Memphis se apresura a reunir a su vieja banda y los desafía a una carrera a toda velocidad para dar el último gran golpe.
</sinopsis>
</pelicula>
</biblioteca>


A partir de este documento generamos el dtd y lo modificamos algo según queramos, quedando el mio de la forma




<!ELEMENT biblioteca ( libro*, pelicula* ) >

<!ELEMENT libro ( personaje*, sinopsis ) >
<!ATTLIST libro autor CDATA #IMPLIED >
<!ATTLIST libro genero CDATA #IMPLIED >
<!ATTLIST libro titulo CDATA #REQUIRED >

<!ELEMENT pelicula ( personaje*, sinopsis ) >
<!ATTLIST pelicula fecha NMTOKEN #IMPLIED >
<!ATTLIST pelicula titulo CDATA #REQUIRED >

<!ELEMENT personaje ( #PCDATA ) >
<!ATTLIST personaje actor CDATA #IMPLIED >
<!ATTLIST personaje nombre CDATA #REQUIRED >

<!ELEMENT sinopsis ( #PCDATA ) >


Este tiene un pequeño problema y es que estaría mejor si los personajes no pertenecieran a un libro sino que fueran incluidos en el, pero para lo que necesito por ahora me vale.

Si creamos otro documento xml como el siguiente:




<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE biblioteca PUBLIC "Biblioteca/Filmoteca" "practica4.dtd">
<biblioteca>
<libro titulo="Eragon" autor="Christopher Paolini" genero="Novela Fantastica">
<personaje nombre="Eragon">
Es el protagonista de la historia, un joven granjero que vive con su tío Garrow y su primo Roran, a las afueras de Carvahall. La historia toma lugar cuando este tiene la edad de 15 años y encuentra una extraña piedra en las Vertebradas.

Eragon es valiente, observador, posee buenas dosis de prudencia y sabe valerse por sí mismo. Su madre, Selena, lo dejó cuando era pequeño a cargo de Garrow, su hermano. Eragon se crió con él y con su primo, Roran. De su padre no conoce nada.
</personaje>
<personaje nombre="Saphira">
Es la dragona acompañante de Eragon, su comunicación con su Jinete es telepática, debido a los rasgos mágicos que los unen. Tiene conciencia propia e inteligencia, por tanto es capaz de discernir y tomar sus propias decisiones. Durante el transcurso de la historia esta crece y evoluciona, adquiriendo nuevas habilidades y desarrollando sus capacidades de dragón. Sus escamas son de color azul zafiro brillante.

Es la última dragona en Alagaësia, por lo que el rey Galbatorix la quiere viva para poder crear una nueva generación de dragones.
</personaje>
<sinopsis>
Esta historia transcurre en el ficticio territorio de Alagaësia. Cuando Eragon encuentra una especie de zafiro de gran tamaño mientras está cazando en el bosque, piensa que su suerte ha cambiado. Él, un muchacho que vive en una modesta granja con su tío Garrow y su primo Roran, cree que vendiéndola podrá comprar carne a Sloan, el carnicero de Carvahall -su pueblo natal-, para poder pasar el frío invierno. Sin embargo, este no la compra al enterarse de que proviene de las misteriosas y peligrosas montañas conocidas como las Vertebradas, por lo que el muchacho la lleva de vuelta a casa.

Una noche la gema se rompe, revelando ser un huevo, y de él emerge un dragón. Este resulta ser una hembra y Eragon la nombra Saphira. De esta manera, Eragon se convierte en un Jinete de Dragón, manteniendo a Saphira en secreto, ignorando por completo a la persecución que el despótico rey Galbatorix ha iniciado para recuperar el huevo. Cuando unas misteriosas criaturas conocidas como Ra'zac, enviadas por Galbatorix, asesinan a su tío, emprende su huida de Carvahall junto a Saphira y al anciano cuentacuentos del pueblo, Brom.

Brom entrena al joven y a la dragona en el uso de la magia y en el combate para prepararlos en su labor como el nuevo Jinete y Dragón, para reiniciar la antigua Orden de Jinetes de Dragón, derrocar al tirano rey y restaurar la paz en Alagaësia. Sin embargo, los sueños de Eragon sobre una bella mujer torcerán su camino para rescatarla de su captor, Durza, el más peligroso sirviente de Galbatorix.
</sinopsis>
</libro>
</biblioteca>


Pasando el dtd vemos que este documento cumple las condiciones y pasa el examen.

Practica 3

Lo que hace el programa es facil de explicar, simplemente es un menú de la asignatura en tu boton derecho, de forma que es mucho más rápido acceder a los lugares frecuentados en clase. Además maximiza la ventana del navegador.


He decidido hacer esto, en principio porque no se me ocurria nada (yo de imaginación 0 está visto), habia pensado modificar las fuentes de las páginas pero, además de que no me salia (tampoco me entretení mucho), no le veía utilidad. Pero al final se me ocurrió lo del menú en el botón derecho, y como eso de estar para atrás ahora al tema 2, luego para atrás y cambiando de tema (sobre todos cuando aún estabamos viendo algo de javascript), me mareaba y al final no sabia donde estaba (jeje), me pareció una buena idea, así que aquí está el resultado. Lo de maximizar la ventana es más por manía mia que por otra cosa pero como resultó facil lo puse



Código del programa



// ==UserScript==

// @name AAP-Nav-BotonDerecho

// @namespace http://geneura.org/projects/greasemonkey

// @description Navegador en el botón derecho por las distintas páginas de AAP

// @include http://geneura.ugr.es/~jmerelo/asignaturas/*

// ==/UserScript==



var head = document.getElementsByTagName('head');



//Crearemos el estilo del menu, para ello creo una etiqueta de CSS y le inserto el codigo

var miStyle = document.createElement('style');


miStyle.innerHTML='.tipo1{position: absolute;background-color: Menu;width: 200px;visibility: hidden;}a.menuitem {font-size: 0.8em; font-family: Arial, Serif; text-decoration: none;}';


//todo esto lo meto al final de la cabecera (donde suele ir el codigo CSS si no va en un archivo aparte)

head[0].appendChild(miStyle);



//Igual que antes creamos una etiqueta pero ahora de javaScript (el codigo fue creado y probado primero en una pagina html para ver si funcionaba)

var miScript = document.createElement('script');


miScript.innerHTML='var menutipo = 1;function sombra(e){ if (document.getElementById) { mimenu = document.getElementById("menurapido") }else if (document.all) { mimenu = document.all.menurapido } if (!e) {var e = window.event} var borde_derecho = document.body.clientWidth - e.clientX; var borde_inferior = document.body.clientHeight - e.clientY; if (borde_derecho < mimenu.offsetWidth){ mimenu.style.left = document.body.scrollLeft + e.clientX - menurapido.offsetWidth + "px"} else{ mimenu.style.left = document.body.scrollLeft + e.clientX + "px"} if (borde_inferior < mimenu.offsetHeight){ mimenu.style.top = document.body.scrollTop + e.clientY - menurapido.offsetHeight} else{ mimenu.style.top = document.body.scrollTop + e.clientY} mimenu.style.visibility = "visible"; return false}function visibilidad(){ if (document.getElementById) { mimenu = document.getElementById("menurapido") }else if (document.all) { mimenu = document.all.menurapido } mimenu.style.visibility = "hidden"}document.oncontextmenu = sombra;document.onclick = visibilidad;';



//Al igual que antes insertamos la etiqueta en la cabecera

head[0].appendChild(miScript);




<
>//Ahora es el turno de crear lo que lleva el menú en sí

//Primero la etiqueta div donde va todo esto con la identificación id=menurapido para que el menu sea esto

var menu = document.createElement('div');

menu.setAttribute('id','menurapido');



//El primer enlace a la pagina principal

//Creo un enlace con su class y su href y lo meto en el div

var enlace1 = document.createElement('a');

enlace1.setAttribute('href','http://geneura.ugr.es/~jmerelo/asignaturas/AAP/');

enlace1.setAttribute('class','menuitem');

//A este enlace (por ser la página principal) lo pongo un poco más grande creando la etiqueta font dentro de a dentro de div

var fuente = document.createElement('font');

fuente.setAttribute('size','4');

var txt1=document.createTextNode('Pagina principal');

//se añade el texto que aparecera en el menu a la etiqueta fuente

fuente.appendChild(txt1);

//se añade la etiqueta fuente al hipervínculo

enlace1.appendChild(fuente);

//se añade el hipervínculo a la etiqueta div

menu.appendChild(enlace1);



//creo el salto de línea

var enlacea = document.createElement('br');

menu.appendChild(enlacea);



//creo la barra horizontal para separar secciones

var enlaceb = document.createElement('hr');

menu.appendChild(enlaceb);



//el título de la sección (este no tiene enlace pero lo remarco con la etiqueta n)

var enlacec = document.createElement('b');

var txtc=document.createTextNode('Temario');

enlacec.appendChild(txtc);

menu.appendChild(enlacec);



var enlacea = document.createElement('br');

menu.appendChild(enlacea);



//Ahora voy creando cada enlace a cada tema

var enlace2 = document.createElement('a');

enlace2.setAttribute('href','http://geneura.ugr.es/~jmerelo/asignaturas/AAP/AAP-Tema-1.mhtml');

var txt2=document.createTextNode('Tema 1: Introducción');

enlace2.setAttribute('class','menuitem');

enlace2.appendChild(txt2);

menu.appendChild(enlace2);



var enlacea = document.createElement('br');

menu.appendChild(enlacea);



var enlace3 = document.createElement('a');

enlace3.setAttribute('href','http://geneura.ugr.es/~jmerelo/asignaturas/AAP/AAP-Taller-1.mhtml');

var txt3=document.createTextNode('Taller 1: Javascript');

enlace3.setAttribute('class','menuitem');

enlace3.appendChild(txt3);

menu.appendChild(enlace3);



var enlacea = document.createElement('br');

menu.appendChild(enlacea);



var enlace4 = document.createElement('a');

enlace4.setAttribute('href','http://geneura.ugr.es/~jmerelo/asignaturas/AAP/AAP-Taller-2.mhtml');

var txt4=document.createTextNode('Taller 2: XML');

enlace4.setAttribute('class','menuitem');

enlace4.appendChild(txt4);

menu.appendChild(enlace4);



var enlacea = document.createElement('br');

menu.appendChild(enlacea);



var enlace4 = document.createElement('a');

enlace4.setAttribute('href','http://geneura.ugr.es/~jmerelo/asignaturas/AAP/AAP-Taller-3.mhtml');

var txt4=document.createTextNode('Taller 3: Servicios Web');

enlace4.setAttribute('class','menuitem');

enlace4.appendChild(txt4);

menu.appendChild(enlace4);



var enlacea = document.createElement('br');

menu.appendChild(enlacea);



//separando secciones

var enlaceb = document.createElement('hr');

menu.appendChild(enlaceb);



//Título de sección

var enlacec = document.createElement('b');

var txtc=document.createTextNode('Prácticas');

enlacec.appendChild(txtc);

menu.appendChild(enlacec);



var enlacea = document.createElement('br');

menu.appendChild(enlacea);



//En lugar de poner el nombre de cada práctica simplemente pondremos Practia1,2,etc, por lo que ahora si podemos hacer un bucle que nos meta todos los enlaces de golpe

for (var prac = 1; prac < 8 ; prac ++ ) {

var enlaceprac = document.createElement('a');

enlaceprac.setAttribute('href','http://geneura.ugr.es/~jmerelo/asignaturas/AAP/AAP-Practica-'+prac+'.mhtml');

var txtprac=document.createTextNode('Práctica '+prac);

enlaceprac.setAttribute('class','menuitem');

enlaceprac.appendChild(txtprac);

menu.appendChild(enlaceprac);

var enlacea = document.createElement('br');

menu.appendChild(enlacea);

}



//separando secciones

var enlaceb = document.createElement('hr');

menu.appendChild(enlaceb);



//Título de sección

var enlacec = document.createElement('b');

var txtc=document.createTextNode('Otros enlaces');

enlacec.appendChild(txtc);

menu.appendChild(enlacec);



var enlacea = document.createElement('br');

menu.appendChild(enlacea);



//Otros enlaces que se suelen usar en la asignatura, al menos yo

var enlace5 = document.createElement('a');

enlace5.setAttribute('href','http://aap-ugr-2007.wikispaces.com/');

var txt5=document.createTextNode('Wiki');

enlace5.setAttribute('class','menuitem');

enlace5.appendChild(txt5);

menu.appendChild(enlace5);



var enlacea = document.createElement('br');

menu.appendChild(enlacea);



var enlace6 = document.createElement('a');

enlace6.setAttribute('href','http://tech.groups.yahoo.com/group/aap-ugr/');

var txt6=document.createTextNode('Lista de correo');

enlace6.setAttribute('class','menuitem');

enlace6.appendChild(txt6);

menu.appendChild(enlace6);



var enlacea = document.createElement('br');

menu.appendChild(enlacea);



var enlace7 = document.createElement('a');

enlace7.setAttribute('href','http://geneura.ugr.es/~jmerelo/asignaturas/AAP/cgi/enviarPracticas.cgi');

var txt7=document.createTextNode('Enviar Prácticas');

enlace7.setAttribute('class','menuitem');

enlace7.appendChild(txt7);

menu.appendChild(enlace7);



var enlacea = document.createElement('br');

menu.appendChild(enlacea);



var enlace7 = document.createElement('a');

enlace7.setAttribute('href','http://geneura.ugr.es/~jmerelo/asignaturas/AAP/planet.cgi');

var txt7=document.createTextNode('Planet');

enlace7.setAttribute('class','menuitem');

enlace7.appendChild(txt7);

menu.appendChild(enlace7);



document.body.appendChild(menu);





//Por último metemos el escript que es el que "llama" al menú y le da forma (la que le hemos puesto en la etiqueta style

var miScript2 = document.createElement('script');




miScript2.innerHTML='if (document.getElementById) { document.getElementById("menurapido").className = "tipo1" } else if (document.all) { document.all.menurapido.className = "tipo1" } ';



document.body.appendChild(miScript2);



//Al final también he visto que siempre estaba maximizando la pantalla del navegador para ver bien el menú o por manía asi que me creado otra aplicación que me maximizara todas las páginas (que perro soy to por no darle a un botoncito), asi que he insertado aqui el pequeño codigo.

var miScript3 = document.createElement('script');


miScript3.innerHTML='window.moveTo(0,0);top.window.resizeTo(screen.availWidth,screen.availHeight);';


head[0].appendChild(miScript3);







Está puesto en la dirección: http://www.fileden.com/getfile.php?file_path=http://www.fileden.com/files/2007/11/7/1570028/aap-menuderecho.zip


Lo he subido en un zip porque el no me dejaba subirlo en la extension .user.js.


El menú queda de la siguiente forma:




Practica 2


El pequeño programa que he hecho o mejor dicho la miniaplicacion es simplemente par que un profesor ponga un listado de notas pudiendo ver cuantos alumnos lleva, la nota media, e incluso le avisa si el alumno ya ha sido metido en el listado. También puede ordenar el listado por nombre (un listado organizado) o por notas (se directamente a quien dar las matriculas de honor).


En el programa que he hecho tengo incluida una deficinicion de clase (Alumno), a la cual llamo cada vez que lo necesito, aunque lo que mayormente hago con la clase es crear los objetos que necesito para operar. Aunque la clase la he creado sin funciones lo mismo podrian estar incluidas la mayor parte de las que tengo pero he preferido no hacerlo porque asi puedo llamar siempre a las funciones sin ningun tipo de restriccion (una mania que tengo de hacer cada cosa lo mas independiente de las demas como se pueda).



Aplicacion Resultante final





<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

<head>

<title>AAP: Practica 2 : Pablo Ignacio Rodríguez Fernández</title>

<script type="text/javascript">

var cadena = "";

// Definición de la clase Alumno

function Alumno (nombre,nota){

this.nombre = nombre;

this.nota = nota;

}



var lista = new Array;



function insertarNota (nombre, nota){

lista[lista.length] = new Alumno (nombre,nota);

calificaciones();

}



function vercalificacion (nota){

var calificacion = "";

if (nota == "NP"){

calificacion = "No Presentado";

}

else if (nota >= 9){

calificacion = "Sobresaliente";

}

else if (nota >= 7){

calificacion = "Notable";

}

else if (nota >= 5){

calificacion = "Aprobado";

}

else{

calificacion = "Suspenso";

}

return calificacion;

}



function notaMedia(){

var media = 0;

for (i in lista){

media += parseFloat(lista[i].nota);

}

media = media / lista.length;

return media;

}



function calificaciones () {

cadena = "<table border=0>";

cadena += "<tr height=20><td width=500><b>Nombre del Alumno</b></td><td><b>Nota Final</b></td></tr>";

for (i in lista) {

//cadena += lista[i].mostrarunalumno();

cadena += "<tr height=20>";

cadena += "<td width=500>" + lista[i].nombre + "</td>";

var calificacion = vercalificacion(lista[i].nota);

cadena += "<td>" + lista[i].nota +"</td>";

cadena += "<td>" + calificacion + "</td>";

cadena += "</tr>";



}

cadena += "<tr></tr><tr><td>Numero total de Alumnos: " + lista.length+"</td>";

cadena += "<td>Nota media: " + notaMedia() + "</td></tr>"

cadena += "</table>";

escribir(cadena);

}



function escribir (text){

document.getElementById('programa').innerHTML=text;

}



function anadirNota(){

nombre = document.getElementById('nombre').value;

nota = document.getElementById('nota').value;

var num_nota = /^(([0-9]\.[0-9]*)|([0-9]|10)|NP)$/ //numero del 0-10

var er_nombre = /^([a-z]|[A-Z]|á|é|í|ó|ú|ñ|ü|\s|\,)+$/ //letras, ',' o espacio repetidos



//comprueba campo nombre

if(!er_nombre.test(nombre)) {

alert('Contenido del campo nombre no válido.')

return false

}



//comprueba campo nota

if(!num_nota.test(nota)) {

alert('Contenido del campo nota no valido (debe ser un numero del 0-10 o NP).')

return false

}

var confirmar = confirm('La nota del alumno '+ nombre +' es ' + nota +'?')

var repetido = false;

if (confirmar){

for (i in lista) {

if(nombre==lista[i].nombre){

var repetido = true;

}

}

if(repetido == false){

insertarNota(nombre, nota);

return true

}

else{

alert('El alumno ya tiene nota')

return false

}

}

else{

return false

}

}



function ordenarporNombre(){

for(var h = 0; h < lista.length-1 ; h++ ){

if(lista[h].nombre > lista[h+1].nombre){

var a = new Alumno (lista[h].nombre,lista[h].nota);

lista[h]= new Alumno (lista[h+1].nombre,lista[h+1].nota);

lista[h+1]=new Alumno (a.nombre,a.nota);

h=-1;

}

}

calificaciones ();

}

function ordenarporNota(){

for(var h = 0; h < lista.length-1 ; h++ ){

if(lista[h].nota < lista[h+1].nota){

var a = new Alumno (lista[h].nombre,lista[h].nota);

lista[h]= new Alumno (lista[h+1].nombre,lista[h+1].nota);

lista[h+1]=new Alumno (a.nombre,a.nota);

h=-1;

}

}

calificaciones ();

}



</script>



</head>



<body>

<center>



<h1>AAP: Practica <x> : Pablo Ignacio Rodríguez Fernández</h1>



<h2>Introducción</h2>



<p>

El pequeño programa que he hecho o mejor dicho la miniaplicacion es simplemente par que un profesor ponga un listado de notas pudiendo ver cuantos alumnos lleva, la nota media, e incluso le avisa si el alumno ya ha sido metido en el listado. También puede ordenar el listado por nombre (un listado organizado) o por notas (se directamente a quien dar las matriculas de honor).





<h2>Primer punto puntuable de la práctica</h2>



<p>

En el programa que he hecho tengo incluida una deficinicion de clase (Alumno), a la cual llamo cada vez que lo necesito, aunque lo que mayormente hago con la clase es crear los objetos que necesito para operar. Aunque la clase la he creado sin funciones lo mismo podrian estar incluidas la mayor parte de las que tengo pero he preferido no hacerlo porque asi puedo llamar siempre a las funciones sin ningun tipo de restriccion (una mania que tengo de hacer cada cosa lo mas independiente de las demas como se pueda).</p>





<h2>Aplicacion Resultante final</h2>



<form>

Nombre del alumno: <input type="text" id="nombre"><br>

Nota del alumno: <input type="text" id="nota"><p>

<input type="button" value="Poner Nota" onClick="anadirNota();"><p>





<input type="button" value="Lista de Alumnos ordenada alfabeticamente" onClick="ordenarporNombre();">

<input type="button" value="Lista de Alumnos ordenada por nota" onClick="ordenarporNota();">



</form>



<div id="programa">

</div>

<hr>

<address><a href="mailto:pabloign@gmail.com">pabloign</a></address>



</center>

</body>

</html>

Bloque T2.10

Hacer un filtro SAX que traduzca el célebre XML casero de etiquetas en español a etiquetas en inglés. Hacerlo en Ruby o en otro lenguaje.




require 'rexml/document'
require 'rexml/streamlistener'
include REXML

file='./casa.xml'
diccionario = {

"micasa"=>"my house",
"habitacion"=>"room",
"mueble"=>"furniture",
"puerta"=>"door",
"aparador"=>"sideboard",
"bañera"=>"bath"}

class Traduccion
include StreamListener

def initialize(traduc)

@escribe = false
@diccionario=traduc
end

def tag_start(name, attributes)
puts "<"+@diccionario[name]+">"

@escribe = true

end

def tag_end(name)
puts ""
@escribe=false
end

def text(texto)
if @escribe
puts @diccionario[texto]
end
end

end

listener = Traduccion.new(palabras)
parser = Parsers::StreamParser.new(File.new(file), listener)
parser.parse

Bloque T2.9

Crear un CGI que responda a un interfaz REST y devuelva un fichero XML.


use CGI qw(:standard);
use XML::Simple;
my $url = param('url');
my $documento = XMLin('casa.xml');
print header( -type => '$url' );
print XMLout($documento);

Bloque T2.7

Hacer un programa que lea un feed RSS dado por el URL y presente los títulos y la fecha. Usar cualquier lenguaje de programación.

El programa que uso es el mismo que hay en la pagina, pero algo modificado.


#!/usr/bin/ruby

require 'rss/1.0'
require 'rss/2.0'

documento = ARGV[0]
file = File.new(documento)
rss = RSS::Parser.parse(file, false)
rss.channel.items.each do |i|
puts "*" + i.title + " Publicado: " + i.pubDate.to_s
end

Bloque T2.4

Diseñar un XSchema para un documento XML que describa una quiniela, incluyendo resultados. Tener en cuenta que una quiniela tiene 15 partidos sólo. Hacer un documento XML que siga ese XML Schema, y validarlo usando Xerces2 o algún otro parser con validación.

el xschema es el siguiente


<?xml version="1.0" encoding="utf-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema">

<element name="quiniela">
<complexType>
<sequence>
<element name="partido" minOccurs="1" maxOccurs="15" >
<complexType>
<element name="Local" type="string" minOccurs="1" maxOccurs="1"></element>
<element name="Visitante" type="string" minOccurs="1" maxOccurs="1"></element>
<element name="Resultado" type="string" minOccurs="1" maxOccurs="1"></element>
</complexType>
</element>
</sequence>
</complexType>
</element>
</schema>



mientras que el documento validado es el siguiente



<quiniela>
<partido>
<local>Madrid</local>
<visitante>Barcelona</visitante>
<resultado>1</resultado>
</partido>
<partido>
<local>Malaga</local>
<visitante>Sevilla</visitante>
<resultado>1</resultado>
</partido>
</quiniela>

Bloque T2.3

Ya se que es un poco tarde pero voy a subir los ejercicios que tenía casi hechos, porque me he dado cuenta de que apenas tenía subidos.

Con los equipos de la liga anteriores, usar diferentes espacio de nombres para el equipo en sí y para sus componentes. Por ejemplo, los elementos que se incluyan dentro de un jugador pueden tener un espacio de nombres, mientras que la descripción de un equipo puede tener otro diferente


<?xml version="1.0" encoding="utf-8"?>

<equipo:Equipo xmlns='http://www.geneaura.org/' xmlns:equipo='http://www.geneaura.org/Equipo' xmlns:jugador='http://www.geneaura.org/jugador' xmlns:entrenador='http://www.geneaura.org/entrenador'>
<equipo:entrenador>
<entrenador:nombre>Nombre entrenador</entrenador:nombre>
<entrenador:edad>43</entrenador:edad>
</equipo:entrenador>
<equipo:jugador>
<jugador:nombre>Nombre jugador</jugador:nombre>
<jugador:posicion>Base</jugador:posicion>
<jugador:altura>189</jugador:altura>
<jugador:edad>23</jugador:edad>
<jugador:numero>5</jugador:numero>
</equipo:jugador>
<equipo:jugador>
<jugador:nombre>Nombre jugador</jugador:nombre>
<jugador:posicion>Alero</jugador:posicion>
<jugador:altura>201</jugador:altura>
<jugador:edad>28</jugador:edad>
<jugador:numero>10</jugador:numero>
</equipo:jugador>
<equipo:jugador>
<jugador:nombre>Nombre jugador</jugador:nombre>
<jugador:posicion>Pivot</jugador:posicion>
<jugador:altura>210</jugador:altura>
<jugador:edad>30</jugador:edad>
<jugador:numero>15</jugador:numero>
</equipo:jugador>
</equipo:Equipo>

viernes, 29 de mayo de 2009

Bloque 3-1

Argumentar en el blog propio la utilidad de los servicios web, y qué posibilidades tienen el futuro


He encontrado algunas cosillas que responden perfectamente (o más o menos) a lo que pide el ejercicio:

En cuanto a la utilidad he visto:

Lo primero que debéis saber, si no lo conocéis ya, es que la tecnología web 2.0 os permite utilizar determinadas aplicaciones web en línea de una manera muy sencilla ya que, en la mayoría de los casos, tan sólo habéis de disponer de un navegador y una conexión a Internet. Así, no necesitáis descargaros miles de programas en vuestro ordenador para realizar todas aquellas actividades que se os pasen por la cabeza o necesitéis por motivos de trabajo.

Además, os permite compartir todo tipo de contenidos, es decir, colgarlos o bajarlos desde Internet y crear o modificar contenidos entre distintos usuarios. Estos servicios web 2.0 son muy sencillos de utilizar y van desde el nivel más básico hasta el más avanzado, aunque muchas veces en este último caso seguramente se os solicite pagar algún sumplemento. Las aplicaciones más básicas suelen ser gratuitas. Aunque la gran mayoría de estos servicios están en versión “beta“, todas ellos suelen funcionar a la perfección.


Si quereis ver algo más os dejo el enlace aquí

En cuanto a la visión futura tenemos

El trabajo sobre la plataforma de servicios Web continuará en el futuro, y aparecerán mejoras en tres áreas fundamentales. En primer lugar, se añadirán servicios de más alto nivel. Todo el mundo está de acuerdo en que debe existir un modo estándar de asegurar servicios Web, rutear mensajes, garantizar una entrega fiable de mensajes, definir semántica transaccional, etc. Estas características de propósito general se expanden más allá de los dominios del problema y no hay ninguna razón por la que cada desarrollador de servicios Web deba implementarlas individualmente. Microsoft, IBM y otros están realizando mucho trabajo en estas áreas. La iniciativa Global XML Web Service Architecture (GXA) define un conjunto de especificaciones sobre cómo implementar estos servicios de infraestructura en términos de mensajes SOAP (por ejemplo, de un modo neutral respecto del protocolo de transporte.

En segundo lugar, seguirán estandarizándose especificaciones. El ciclo de vida de las especificaciones de servicios Web típicamente progresa desde una propuesta hasta un estándar de facto y desde éste hasta un estándar real. Con SOAP 1.2 y WSDL 1.2 las peculiaridades finales están siendo elaboradas de las especificaciones SOAP y WSDL y algunas de las especificaciones de servicios de mayor nivel, como WS-Security, ya están en el periodo "de facto" en el proceso de estandarización. Las empresas siguen proponiendo nuevas especificaciones como añadidos a la plataforma de servicios Web y la industria en su conjunto necesitará acordar cuáles adoptar. Esas especificaciones necesitarán a continuación ser estandarizadas.

En tercer lugar, los kits de herramientas y marcos de trabajo seguirán mejorando. Además de servicios de más alto nivel como la seguridad y los objetos adjuntos, se añadirá soporte para protocolos de transporte alternativos como SMTP o TCP. De modo más importante, los modelos de programación migrarán desde los servicios de tipo RPC hacia servicios centrados en documentos, para promover un acoplamiento débil. Todos estos cambios ocurrirán en paralelo, mientras los desarrolladores continúan desarrollando e implantando sistemas basados en servicios Web.

Avances de futuro

Llegados a este punto, estaremos preguntándonos cómo podemos utilizar los servicios Web cuando la plataforma todavía está evolucionando. Las herramientas y marcos de trabajo de los servicios Web actuales proporcionan suficiente funcionalidad básica para desarrollar interesantes aplicaciones distribuidas que envían mensajes SOAP sobre HTTP. Algunos servicios de mayor nivel como WS-Security están empezando a cuajar con el soporte de diversas herramientas nuevas como el kit Web Services Development Kit. Otros servicios están todavía en fase de desarrollo preliminar a medida que las especificaciones se van revisando y las primeras implementaciones exponen áreas en las que las especificaciones necesitan solidificarse. Mientras tanto, podemos apoyarnos en mecanismos HTTP tradicionales para implementar seguridad y demás características.

Si queremos desarrollar servicios Web utilizando herramientas de Microsoft, tenemos varias opciones. Si todavía estamos utilizando Visual Studio 6.0 o algún otro entorno de desarrollo que no soporta el desarrollo de código gestionado, podemos crear y consumir servicios Web utilizando el kit de herramientas SOAP Toolkit. Si estamos utilizando .NET, podemos focalizarnos en los métodos Web de ASP.NET (a esto hace referencia la mayor parte de la documentación de .NET sobre los servicios Web). En cualquier caso, podemos aprender tanto como queramos sobre cómo funcionan los protocolos de mensajería y metadatos de los servicios Web. Cuanto más comprendamos la fontanería, más fácil será desarrollar nuestros propios servicios y utilizar servicios desarrollados por los demás.

También podemos experimentar con las nuevas especificaciones. La versión preliminar del kit Microsoft WSDK Technology Preview proporciona un soporte preliminar para las especificaciones WS-Security, WS-Routing y DIME. Podemos también implementar especificaciones por nosotros mismos, tanto utilizando extensiones sobre uno de los marcos de trabajo o kits de herramientas (por ejemplo, SoapExtensions en ASP.NET), como crear nuestra propia pila SOAP utilizando XML plano y las APIs HTTP. Esta opción no es para todo el mundo, pero si tenemos tiempo y recursos, obtendremos pronto una avanzada funcionalidad. Además, contribuiremos al desarrollo de la plataforma. El entendimiento colectivo de SOAP Y WSDL se mejoró sustancialmente gracias al intento de implementación de sistemas basados en ambos estándares por parte de múltiples usuarios. Cuanto más estrechamente trabajen los usuarios con las nuevas especificaciones, mejor resultará la plataforma de servicios Web global.

También os pongo el enlace aquí

Practica 6

¿Qué hace esta aplicación?



Esta aplicación carga una base de datos rss y muestra una lista con los títulos de las noticias, libros o lo que contenga el rss, de forma que la pinchar sobre ellos nos muestra la noticia al completo y si pinchas sobre el título (que aparece en la parte superior) pasa a la siguiente noticia.



En mi caso lo he hecho para una base de libros formada como un rss (para que pudiera también abrir los rss de noticias de la práctica anterior). La página principal tiene 3 casillas desplegables: en la primera seleccionamos si cargamos la base de libros o las noticias; en la segunda seleccionamos el número de noticias a mostrar en la lista (he puesto un máximo de 10 porque algunos rss de noticias no tenían más y tampoco lo consideraba necesario); en la tercera seleccionamos el género del libro haciendo una especie de filtrado (esta solo funciona con "Mi biblioteca").



Ejemplo: si nosotros seleccionamos la biblioteca en la primera casilla, con solo detectar el cambio ya se carga la lista igual que cuando se modifica cualquiera de las otras casillas, se nos cargan (por defecto) 10 libros. Si cambiamos la segunda casilla aparecerán los primeros x libros que le indiques. Y si variamos la tercera casilla solo se te muestran los primeros x libros del género que selecciones (hay muy pocos libros así que si marcas más de los que tiene solo te muestra los que tiene valga la redundancia). Si una vez tengamos la lista deseada pinchamos sobre un título (esto también funciona para las noticias), vemos el resumen del libro (en caso de noticias la noticia seleccionada), y si pinchamos sobre el título pasamos al libro (o noticia) siguiente, de forma que si tenemos seleccionado género el siguiente del género. Si pinchamos sobre "El Señor de los Anillos" y tenemos marcado el género "Fantástico" y luego pinchamos sobre el título pasamos a "El Hobbit" (puesto que es el siguiente del género), en lugar de "La Isla del Tesoro" que sería el siguiente libro (si tenemos ninguno en género pasa a este), y si no hay ninguno detrás de este vuelve al primero.


Esta aplicación está orientada para una librería pero pongo lo de las noticias por ver que usos, además de para los que se ha propuesto, tiene, como, por ejemplo un gestor de noticias.


Aplicación servidor



El servidor es muy parecido al de la práctica anterior y se encarga de recibir la url de donde se encuentra el rss en cuestión y crear un rss de salida que lo tomará el cliente con los x primeros elementos o items, donde x será un parámetro que también se le pasa. El servidor está escrito en perl y su código es el siguiente:


#!/usr/bin/perl

use CGI qw(:standard);
use XML::RSS;
use LWP::Simple qw(get);

my $numero_elementos = param('num_elementos');
my $url = param('url');
#Baja fichero
my $rdf = get($url);
my $rss = new XML::RSS;
$rss->parse($rdf);
my $rss_salida = new XML::RSS;
$rss_salida->channel( title => 'Resumen feed',
link => $url,
description => 'Resumiendo el feed' );
print header( -type => 'application/xhtml+xml' );

for (my $i = 0; $i < $numero_elementos;$i ++ ) {
$rss_salida->add_item( title => $rss->{'items'}[$i]->{'title'},
link => $rss->{'items'}[$i]->{'link'},
pubDate => $rss->{'items'}[$i]->{'pubDate'},
description => $rss->{'items'}[$i]->{'description'},
category => $rss->{'items'}[$i]->{'category'} );
}
print $rss_salida->as_string;

Aplicación cliente



El cliente se encarga de ver que hay en los valores de las casillas y pedir al servidor lo necesario, y una vez que tiene los datos llama a las funciones necesarias para mostrar, en la parte de abajo donde en el html tenemos con un div con id=RSS, lo mencionado anteriormente.


var request;
var variable;
var html="<hr>";
var items;

Esta función es la que se encarga de llamar al servidor, pasandole la dircción de la fuente, y obtener los datos necesarios para trabajar con ellos en la funcion escribe_RSS


function pide_RSS() {
html="<hr>";
request = new XMLHttpRequest();
var url=document.getElementById('feed').value;
//var cuantos=document.getElementById('cuantos').value;
var peticion_str = 'cgi-bin/XMLvar_2.cgi?url='+encodeURIComponent(url)+'&num_elementos='+10;
request.open('GET', peticion_str , true);
request.onreadystatechange= escribe_RSS;
request.send(null);
}

Esta función trata con los datos que recibimos del servidor y mostramos las listas de elementos, estas listan tendrán el tamaño que aparece en segundo seleccionable del html. Si tenemos algún género seleccionado nos muestra solo los libros de este género.


function escribe_RSS(){
if ( request.readyState == 4 ) {
if ( request.status == 200 ) {
// alert(request.responseText);
var doc = request.responseXML;
var root=doc.documentElement;
var cuantos=document.getElementById('cuantos').value;
var quegenero=document.getElementById('genero').value;
var k = 0;
items=root.getElementsByTagName('item');
for ( var i = 0; i < items.length; i ++ ){

var title = items[i].getElementsByTagName('title')[0];
var genero = items[i].getElementsByTagName('link')[0];
if (quegenero == 'Ninguno'){
k++;
html += "<dt><button onClick='prueba"+i+"()'>"+title.firstChild.data+ "</button></dt>";
if (k == cuantos){
i=items.length;
}
}
else if (quegenero == genero.firstChild.data){
k++;
html += "<dt><button onClick='prueba"+i+"()'>"+title.firstChild.data+ "</button></dt>";
if (k == cuantos){
i=items.length;
}
}
}
html += "";
document.getElementById('RSS').innerHTML=html;
}
}
}

Esta función es casi igual que la primera, es decir, que llama al servidor con la url y el número de elementos necesarios para trabajar en este caso con escribe_otro. Al volver a llamar al servidor estamos recargando continuamente la los datos, de forma que estos son siempre los más actuales respecto a la base de datos, de forma que si se cambia algo en la base de datos aparece incluso en cuanto pinchamos en un título.


function prueba(){

request = new XMLHttpRequest();
var url=document.getElementById('feed').value;
var cuantos=document.getElementById('cuantos').value;
var peticion_str = 'cgi-bin/XMLvar_2.cgi?url='+encodeURIComponent(url)+'&num_elementos='+cuantos;
request.open('GET', peticion_str , true);
request.onreadystatechange= escribe_otro;
request.send(null);

}

Esta función toma el item que se ha pinchado y muestra este con su descripción, y nos crea el trozo de la página en el que se nos muestra el título junto con su resumen o noticia, de forma que al pinchar sobre este pasamos al siguiente título del género.


function escribe_otro(){
if ( request.readyState == 4 ) {
if ( request.status == 200 ) {
// alert(request.responseText);
var quegenero=document.getElementById('genero').value;

html = "<hr>";
var title = items[variable].getElementsByTagName('title')[0];
var description = items[variable].getElementsByTagName('description')[0];
var genero = items[variable].getElementsByTagName('link')[0];
variable = variable + 1;
if (variable == items.length){
variable = 0;
}
if (quegenero == genero.firstChild.data || quegenero == 'Ninguno'){
html += "<dt><button onClick='prueba"+variable+"()'><font size='+3'>"+title.firstChild.data+ "</font></button><p>"+description.firstChild.data+"</p></dt>";
}
else{
for (var n=variable;n<items.length;n++){
var genero = items[n].getElementsByTagName('link')[0];
if (quegenero == genero.firstChild.data){
var title = items[n].getElementsByTagName('title')[0];
var description = items[n].getElementsByTagName('description')[0];
variable = n+1;
html += "<dt><button onClick='prueba"+variable+"()'><font size='+3'>"+title.firstChild.data+ "</font></button><p>"+description.firstChild.data+"</p></dt>";
n=items.length
}
if (n == (items.length-1)){
n=-1;
}
}
}


html += "";
document.getElementById('RSS').innerHTML=html;
}
}
}




Estas funciones se encargan de indicarnos qué título se ha pinchado y llamar a la función prueba para que cargue la página



function prueba0(){
variable = 0;
prueba();
}
function prueba1(){
variable = 1;
prueba();
}
function prueba2(){
variable = 2;
prueba();
}
function prueba3(){
variable = 3;
prueba();
}
function prueba4(){
variable = 4;
prueba();
}
function prueba5(){
variable = 5;
prueba();
}
function prueba6(){
variable = 6;
prueba();
}
function prueba7(){
variable = 7;
prueba();
}
function prueba8(){
variable = 8;
prueba();
}
function prueba9(){
variable = 9;
prueba();
}

El documento HTML que he usado para llamar a las funciones anteriores es:


&#60!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"&#62
&#60html&#62
&#60head&#62
&#60title&#62BIBLIOTECA dinámica&#60/title&#62
&#60script type='application/javascript' src='peticion.js' &#62&#60/script&#62
&#60/head&#62

&#60body&#62
&#60h1&#62BIBLIOTECA&#60/h1&#62
&#60p&#62Busca el libro que deseas y mira de que trata, y si te gusta, pues a comprarlo :-)&#60/p&#62
&#60p&#62También puedes ver algunas noticias interesantes, para ello asegúrate de que el seleccionable de género está puesto en ninguno
&#60div id='formulario'&#62


&#60select name="feed" id='feed' size="1" onChange='pide_RSS()'&#62
&#60option&#62 Elegir feed
&#60option value="http://www.fileden.com/files/2007/11/7/1570028/biblioteca.xml"&#62 Mi biblioteca
&#60option value="http://www.ideal.es/granada/rss/feeds/ultima.xml"&#62 Ideal
&#60option value="http://rss.marca.com/rss/descarga.htm?data2=385"&#62 Marca
&#60option value="http://feeds.weblogssl.com/xataka2.xml"&#62 Xataka
&#60option value="http://feeds.feedburner.com/NoPuedoCreerQueLoHayanInventado.xml"&#62Nolopuedocreer
&#60/select&#62
&#60select name="cuantos" id='cuantos' size="1" onChange='pide_RSS()'&#62
&#60option value="10"&#62 10
&#60option value="9"&#62 9
&#60option value="8"&#62 8
&#60option value="7"&#62 7
&#60option value="6"&#62 6
&#60option value="5"&#62 5
&#60option value="4"&#62 4
&#60option value="3"&#62 3
&#60option value="2"&#62 2
&#60option value="1"&#62 1
&#60/select&#62
&#60select name="genero" id='genero' size="1" onChange='pide_RSS()'&#62
&#60option value="Ninguno"&#62 Ninguno
&#60option value="Aventuras"&#62 Aventuras
&#60option value="Ficcion"&#62 Ficción
&#60option value="Intriga"&#62 Intriga
&#60/select&#62


&#60div id='RSS'&#62 &#60/div&#62

&#60hr&#62
&#60p&#62&#60font size='-1' color='red'&#62&#60b&#62Ejemplo de uso:&#60/b&#62 si nosotros seleccionamos la biblioteca en la primera casilla, con solo detectar el cambio ya se carga la lista igual que cuando se modifica cualquiera de las otras casillas, se nos cargan (por defecto) 10 libros. Si cambiamos la segunda casilla aparecerán los primeros x libros que le indiques. Y si variamos la tercera casilla solo se te muestran los primeros x libros del género que selecciones (hay muy pocos libros así que si marcas más de los que tiene solo te muestra los que tiene valga la redundancia). Si una vez tengamos la lista deseada pinchamos sobre un título (esto también funciona para las noticias), vemos el resumen del libro (en caso de noticias la noticia seleccionada), y si pinchamos sobre el título pasamos al libro (o noticia) siguiente, de forma que si tenemos seleccionado género el siguiente del género. Si pinchamos sobre "El Señor de los Anillos" y tenemos marcado el género "Fantástico" y luego pinchamos sobre el título pasamos a "El Hobbit" (puesto que es el siguiente del género), en lugar de "La Isla del Tesoro" que sería el siguiente libro (si tenemos ninguno en género pasa a este), y si no hay ninguno detrás de este vuelve al primero.&#60/font&#62&#60/p&#62
&#60/body&#62
&#60/html&#62

Y funciona perfectamente


El funciona bien para lo que lo he probado pero he de reconocer que no he trabajado con un biblioteca muy grande, pero el adaptar el programa a los problemas que pueda tener creo que sería más bien de diseño web y trabajar con lo que te imprime el cliente, con lo que sería, principio sencillo, pero a mi pesar (ya que me gustaría ver si podría hacer una base de datos de los libros de mi casa y con esto puedo verlos desde cualquier sitio y de forma sencilla), a las alturas de curso que estamos y todas las entregas de prácticas y los examenes aquí mismo no puedo entretenerme mucho con ninguna práctica. En definitivamente el programa me ha funcionado bien aunque puede que en algún sitio se pueda optimizar algo, como siempre.


Puedes ver como funciona aquí