Download Generador automático de código HTML válido

Document related concepts
no text concepts found
Transcript
PROYECTO FIN DE CARRERA
Título
Generador automático de código HTML válido
Autor/es
Ernesto Vara Meiro
Director/es
Eduardo Sáenz de Cabezón Irigaray
Facultad
Facultad de Ciencias, Estudios Agroalimentarios e Informática
Titulación
Proyecto Fin de Carrera
Departamento
Matemáticas y Computación
Curso Académico
2012-2013
Generador automático de código HTML válido, proyecto fin de carrera
de Ernesto Vara Meiro, dirigido por Eduardo Sáenz de Cabezón Irigaray (publicado por la
Universidad de La Rioja), se difunde bajo una Licencia
Creative Commons Reconocimiento-NoComercial-SinObraDerivada 3.0 Unported.
Permisos que vayan más allá de lo cubierto por esta licencia pueden solicitarse a los
titulares del copyright.
©
©
El autor
Universidad de La Rioja, Servicio de Publicaciones, 2013
publicaciones.unirioja.es
E-mail: [email protected]
Resumen
Este proyecto es el inicio de una herramienta para corregir errores en archivos
HTML 4.01 Strict.
El abanico de errores que podríamos encontrarnos es muy amplio, pero por las
condiciones que supone un PFC en cuanto a tiempo, solo hemos conseguido
que corrija un número determinado de errores, aunque está diseñado de modo
que queda abierto para que cualquiera pueda añadir de forma sencilla nuevas
soluciones a distintos errores que nosotros no hemos llegado a corregir.
El problema de cómo enviar el archivo al w3c con el lenguaje escogido (JAVA)
ha marcado el proyecto, llegando incluso a tener resultados menos eficientes
de los esperados.
1
2
Contenido
Resumen ......................................................................................................................................1
Introducción ..................................................................................................................................5
Documento de objetivos del Proyecto ..........................................................................................6
Alcance del Proyecto ................................................................................................................6
División de tareas .....................................................................................................................6
Riesgos.....................................................................................................................................7
Calendario ................................................................................................................................7
Estructura de Descomposición del Proyecto (EDP) ..................................................................9
Diagrama de Gantt .................................................................................................................10
Gestión del proyecto ..................................................................................................................11
Análisis .......................................................................................................................................13
Descripción del validador W3C ...............................................................................................13
Antecedentes ..........................................................................................................................16
Tipología de errores ................................................................................................................19
Lista de requisitos ...................................................................................................................22
Arquitectura Cliente-Servidor ..................................................................................................23
Diseño ........................................................................................................................................24
Diagrama de Casos de Uso ....................................................................................................24
Diagrama de Actividad ............................................................................................................26
Diagrama de Clases ...............................................................................................................27
Pruebas ..................................................................................................................................29
Implementación ..........................................................................................................................30
El paquete errores ................................................................................................................31
El paquete interfazGráfica....................................................................................................53
El paquete Principal .............................................................................................................69
Instrucciones de uso ..................................................................................................................70
Pruebas ......................................................................................................................................73
Pruebas simples .....................................................................................................................73
Pruebas de páginas externas .................................................................................................80
Conclusiones ..............................................................................................................................83
Bibliografía .................................................................................................................................84
Anexo: Reuniones ......................................................................................................................85
3
4
Introducción
El proyecto va a consistir en un generador de código html válido, el proyecto
realizará la función de encontrar las partes del documento que incumplan las
reglas del w3c y las corregirá automáticamente.
Este proceso es complejo y obviamente sería imposible corregir todo tipo de
fallos, así que el proyecto intentará arreglar los fallos más comunes y fáciles de
detectar.
La forma en la que el Generador de código html válido va a funcionar será la
siguiente:
1. Se pedirá que se introduzca un documento html.
2. El proyecto enviará dicho documento al w3c .
3. El proyecto asimilará las reglas que incumpla el documento.
4. El proyecto modificará el documento para solucionar las reglas
incumplidas y convertirlo en html válido.
5
Documento de objetivos del Proyecto
Alcance del Proyecto
Este proyecto forma parte de la realización de una aplicación de escritorio
mediante la cual se podrá:
 Enviar un archivo HTML al w3c para averiguar las reglas incumplidas

Será capaz de recoger los errores del w3c y corregirlos

Identificar qué tipos de errores podrían ser corregidos automáticamente

Implementar procedimientos automáticos para corregir errores
susceptibles de corrección.

(Posible ampliación) Interacción con el usuario
Actividades de apoyo al Alcance del Proyecto:
Se utilizará documentación sobre:
 html

w3c

java
Se irá dando parte del estado del proyecto periódicamente a Eduardo y se
harán reuniones para valorar el estado del mismo.
División de tareas
Las personas que forman parte del proyecto, de forma directa o indirecta son:
Ernesto Vara: Director del proyecto
Decisiones a tomar: Todas
Dedicación: Completa
Eduardo Sáenz: Tutor
Decisiones a tomar: Cualquiera en caso de que lo estime
oportuno
Dedicación: Esporádica
Miembros del tribunal
Decisiones a tomar: La nota final del proyecto
Dedicación: Los días necesarios para leer la memoria y el día de
la defensa
6
Riesgos
Que haya tantos errores que sea imposible corregirlos todos
Que unos errores lleven a otros
Que solucione mal los errores
No saber discriminar bien los errores
Que el plan de pruebas sea demasiado grande
Falta de experiencia a la hora de planificar el proyecto
Calendario
2011
L
M
M
J
V
S
D
L
M
2
9
16
23
30
FEBRERO
1
7
8
14 15
21 22
28
JUNIO
ENERO
3
4
10 11
17 18
24 25
31
5
12
19
26
6
13
20
27
7
14
21
28
1
8
15
22
29
MAYO
2
3
9 10
16 17
23 24
30 31
4
11
18
25
5
12
19
26
6
13
20
27
7
14
21
28
1
8
15
22
29
2
9
16
23
30
3
10
17
24
4
11
18
25
3
10
17
24
31
V
S
D
L
FEBRERO
SEPTIEMBRE
6
13
20
27
M
J
V
5
12
19
26
6
13
20
27
7
14
21
28
L
M
M
J
D
L
MARZO
1
7
8
14 15
21 22
28 29
M
M
3
10
17
24
4
11
18
25
5
12
19
26
6
13
20
27
1
8
15
22
29
2
9
16
23
30
3
10
17
24
4
11
18
25
5
12
19
26
1
2
NOVIEMBRE
4
11
18
25
5
12
19
26
6
13
20
27
7
14
21
28
8
15
22
29
9
16
23
30
1
8
15
22
29
M
M
J
V
S
D
M
7
14
21
28
J
V
S
D
2
9
16
23
30
3
10
17
24
31
4
11
18
25
5
12
19
26
6
13
20
27
7
14
21
28
1
8
15
22
29
2
9
16
23
30
3
10
17
24
31
2
9
16
23
30
3
10
17
24
4
11
18
25
5
12
19
26
6
13
20
27
M
J
V
S
D
JULIO
4
11
18
25
7
14
21
28
5
12
19
26
L
M
M
J
V
S
D
6
13
20
27
7
14
21
28
1
8
15
22
29
2
9
16
23
30
3
10
17
24
3
10
17
24
31
4
11
18
25
5
12
19
26
6
13
20
27
7
14
21
28
ABRIL
2
9
16
23
OCTUBRE
1
8
15
22
29
S
6
13
20
27
4
11
18
25
5
12
19
26
AGOSTO
1
2
8
9
15 16
22 23
29 30
DICIEMBRE
5
12
19
26
6
13
20
27
7
14
21
28
1
8
15
22
29
2
9
16
23
30
3
10
17
24
31
4
11
18
25
L
M
M
J
V
S
D
ABRIL
2
3
9
10
16 17
23 24
30
4
11
18
25
5
12
19
26
6
13
20
27
7
14
21
28
1
8
15
22
29
1
8
15
22
29
2
9
16
23
30
3
10
17
24
31
4
11
18
25
5
12
19
26
DICIEMBRE
3
4
5
10 11 12
17 18 19
24 25 26
31
6
13
20
27
7
14
21
28
1
8
15
22
29
2
9
16
23
30
2012
ENERO
2
3
9 10
16 17
23 24
30 31
MAYO
1
7
8
14 15
21 22
28 29
4
11
18
25
5
12
19
26
6
13
20
27
7
14
21
28
1
8
15
22
29
2
9
16
23
30
3
10
17
24
31
4
11
18
25
5
12
19
26
6
13
20
27
7
14
21
28
1
8
15
22
29
2
9
16
23
30
4
11
18
25
3
10
17
24
4
11
18
25
5
12
19
26
6
13
20
27
7
14
21
28
1
8
15
22
29
2
9
16
23
30
3
10
17
24
OCTUBRE
1
2
3
8
9
10
15 16 17
22 23 24
29 30 31
4
11
18
25
5
12
19
26
6
13
20
27
7
14
21
28
7
14
21
28
1
8
15
22
29
JUNIO
SEPTIEMBRE
3
10
17
24
2
9
16
23
6
13
20
27
5
12
19
26
6
13
20
27
4
11
18
25
5
12
19
26
L
MARZO
6
13
20
27
7
14
21
28
1
8
15
22
29
JULIO
2
3
9 10
16 17
23 24
30 31
4
11
18
25
5
12
19
26
6
13
20
27
7
14
21
28
1
8
15
22
29
1
8
15
22
29
2
9
16
23
30
3
10
17
24
4
11
18
25
5
12
19
26
2
9
16
23
30
3
10
17
24
31
4
11
18
25
NOVIEMBRE
5
12
19
26
6
13
20
27
7
14
21
28
AGOSTO
6
13
20
27
7
14
21
28
7
Inicio del proyecto 3 de Octubre del 2011
Planificación Inicial del proyecto:
 Octubre : Creación del DOP

Noviembre: Creación del Análisis

Diciembre: Creación del Diseño

Febrero y Marzo: Implementación

Abril: Pruebas

Mayo y Junio: Creación de la memoria y repaso de todo el proyecto
 Fecha de entrega prevista: 11/06/2012
 Número de días trabajados: 147
 Número de horas al día: 1 y media
 Resumen del número de horas: 214.5 horas
8
Estructura de Descomposición del Proyecto (EDP)
9
Diagrama de Gantt
Tarea
Creación del DOP
Creación del Análisis
Creación del Diseño
Implementación
Pruebas
Gestión del proyecto
TOTAL
Horas estimadas
31.5
33
25.5
64.5
31.5
28.5
214.5
10
Gestión del proyecto
Debido a que el año pasado estaba acabando las carreras de ITIG y
Matemáticas me quedó muy poco tiempo para el proyecto, lo que llevó a que al
final aunque estaba acabado, no estaba lo suficientemente completo como
para entregarlo por lo que decidimos no presentarlo en Junio.
Como era poco lo que tenía que hacer empecé este curso en Febrero.
El calendario de este curso 2012/13:
2013
L
M
ENERO
1
7
8
14 15
21 22
28 29
M
J
V
S
D
2
9
16
23
30
3
10
17
24
31
4
11
18
25
5
12
19
26
6
13
20
27
1
8
15
22
29
2
9
16
23
30
3
10
17
24
31
4
11
18
25
5
12
19
26
SEPTIEMBRE
2
3
4
9 10 11
16 17 18
23 24 25
30
5
12
19
26
6
13
20
27
7
14
21
28
1
8
15
22
29
MAYO
6
13
20
27
7
14
21
28
L
M M
FEBRERO
J
4
11
18
25
7
14
21
28
5
12
19
26
6
13
20
27
V
S
D
1
8
15
22
2
9
16
23
3
10
17
24
2
9
16
23
30
6
13
20
27
JUNIO
5
12
19
26
6
13
20
27
7
14
21
28
1
8
15
22
29
OCTUBRE
1
2
7
8
9
14 15 16
21 22 23
28 29 30
3
10
17
24
31
4
11
18
25
5
12
19
26
3
10
17
24
4
11
18
25
L
M
MARZO
M
J
V
S
D
4
11
18
25
5
12
19
26
6
13
20
27
7
14
21
28
1
8
15
22
29
2
9
16
23
30
3
10
17
24
31
JULIO
1
2
8
9
15 16
22 23
29 30
3
10
17
24
31
4
11
18
25
5
12
19
26
6
13
20
27
7
14
21
28
7
14
21
28
1
8
15
22
29
2
9
16
23
30
3
10
17
24
5
12
19
26
M
J
V
S
D
3
10
17
24
4
11
18
25
5
12
19
26
6
13
20
27
7
14
21
28
7
14
21
28
1
8
15
22
29
2
9
16
23
30
3
10
17
24
31
4
11
18
25
5
12
19
26
6
13
20
27
7
14
21
28
AGOSTO
NOVIEMBRE
4
11
18
25
L
M
ABRIL
1
2
8
9
15 16
22 23
29 30
6
13
20
27
5
12
19
26
6
13
20
27
DICIEMBRE
2
3
4
9 10 11
16 17 18
23 24 25
30 31
Febrero: Revisión del Análisis
Marzo: Revisión del Diseño
Abril-Mayo: Revisión de la Implementación
Junio: Revisión de las pruebas
Julio: Entrega de la memoria y defensa.
 Fecha de entrega: 08/07/2013
 Número de días trabajados: 18 semanas trabajadas
 Número de horas a la semana: 5 horas
 Resumen del número de horas total: 90+214.5=304.5 horas
11
1
8
15
22
29
Tarea
Revisión del Análisis
Revisión del Diseño
Revisión de la Implementación
Revisión de las Pruebas
Gestión del proyecto
TOTAL
Horas estimadas
20
15
35
15
5
90
Tiempo dedicado al proyecto
En la siguiente tabla se muestra lo que me costó realmente contando
ambos cursos
Tarea
Creación del DOP
Creación del Análisis
Creación del Diseño
Implementación
Pruebas
Gestión del proyecto
TOTAL
Horas
35
30+10
20+10
90+50
20+20
15+10
310
Horas estimadas
31.5
33+20
25.5+15
64.5+35
31.5+15
28.5+5
304.5
El DOP me costó más de lo previsto porque era el primero que hacía.
El Análisis al dejarme bastantes cosas lo he tenido que rehacer bastantes
veces, aun así me ha costado menos de los previsto.
El Diseño al estar acostumbrado a hacerlo durante la carrera tardé menos
de lo previsto.
La Implementación fue lo que más me costó del proyecto, bastante más de
lo que había planeado, seguramente porque el primer Diseño que hice no
me ayudó bastante.
Las Pruebas me costaron menos de lo previsto, y la Gestión del proyecto
también, debido a que puse más horas por que no sabía muy bien de que
se trataba.
En resumen, me ha costado casi todo menos de lo previsto excepto la
implementación, y gracias a eso las horas trabajadas son casi iguales que
las horas estimadas.
12
Análisis
Descripción del validador W3C
En esta sección vamos a describir el validador w3c, que es la herramienta que
usaremos para detectar los posibles errores que tengan los documentos html
que pasemos.
Antes de describir el Validador W3C, una pequeña definición de lo que es el
W3C según su web oficial en español (www.w3c.es):
El World Wide Web Consortium (W3C) es una comunidad internacional que
desarrolla estándares que aseguran el crecimiento de la Web a largo plazo
El validador es un servicio gratuito del W3C que ayuda a comprobar que los
documentos Web cumplen esos estándares.
La mayoría de los documentos Web están escritos con lenguajes de marcas,
como HTML o XHTML. Estos lenguajes están definidos por las
especificaciones técnicas, que suelen incluir una gramática formal de lectura
mecánica (y vocabulario). El acto de comprobación de que un documento
cumple estas restricciones se llama validación, y esto es lo que el Validador
HTML hace.
El validador puede procesar documentos escritos en la mayoría de los
lenguajes de marcas, nosotros nos centraremos en HTML 4.01 Strict
HTML 4.01 es una revisión de la Recomendación HTML 4.0 lanzado por
primera vez el 18 de diciembre de 1997. La revisión corrige errores menores
que se han encontrado desde entonces. La especificación completa de HTML
4.01 se encuentra en la siguiente página: http://www.w3.org/TR/html401
Funcionamiento:
A través de http://validator.w3.org se puede validar código HTML de tres
formas:
1. Pasándole una URL
13
2. Pasándole un archivo desde tu ordenador
3. Copiando el código
A parte de la forma en la que le pasemos el documento a verificar también
podemos elegir otras opciones:
Una vez pasado el documento y elegidas las opciones, se pulsa “check” y el
validador nos devuelve los errores que haya podido tener.
Si el documento no contiene errores, el validador te da la opción de poner un
icono en tu página web para que muestre que ha pasado la validación:
Aquí se pueden encontrar todos los iconos http://www.w3.org/QA/Tools/Icons
14
Autoría:
Los directores del W3C son Tim Berners-Lee(inventor de la World Wide
Web,Biografía) y el Dr. Jeffrey Jaffe( Director ejecutivo,Biografía).
En total el equipo del W3C está compuesto de 65 miembros, divididos en las
áreas de Gestión, Apoyo administrativo, Área de Negocios, Comunicaciones,
Interacción, Sistemas, Tecnología y Sociedad, Web ubicua e Iniciativa de
Accesibilidad Web.
El primer validador de HTML lo crearon Dan Connolly y Mark Gaither .
El servicio de Iconos de validación del W3C fue creado por Gerald Oskoboiny.
La Documentación y las Explicaciones de los errores fueron escritas
originalmente por Scott Bigham.
El encargado del diseño de la interfaz fue Valerio Proietti.
El validador usa Perl como lenguaje de programación y muchos módulos de
código abierto de Perl.
Documentación
A continuación pongo una serie de webs de interés acerca del validador:
Guía de usuario: http://validator.w3.org/docs/users.html (inglés)
Especificación de HTML 4.01: http://www.w3.org/TR/html4/ (inglés)
Ayuda y FAQ : http://validator.w3.org/docs/help.html (inglés)
Página del W3C España http://www.w3c.es/
15
Antecedentes
En esta sección voy a exponer algunas aplicaciones que tienen una
funcionalidad parecida a la de este proyecto.
Hay bastantes aplicaciones y/o complementos que permiten corregir una
página web , la más famosa, por estar dentro del propio W3C ,es HTML-Tidy.
HTML-Tidy está incorporado en el validador W3C, sólo hace falta marcar su
casilla para que funcione.
Vamos a comprobar su funcionamiento introduciendo por ejemplo una página
de la UR.
Contiene 14 errores HTML 4.01 Transitional , y además de los errores nos
devuelve el código corregido.
16
Si ahora pasamos éste código por el validador vemos que nos ha corregido
bastantes errores, pero no todos, al igual que nuestra aplicación, es imposible
corregir todo.
17
Otra aplicación que ya existe, quizá la más parecida a la nuestras, es Jtidy.
Su página web es : http://jtidy.sourceforge.net/
Es un fichero ejecutable java .jar que lo puedes usar desde la línea de
comando o añadiéndolo a cualquier desarrollador java como Eclipse y usarlo.
Su funcionamiento es similar a los demás “tidy”, le pasas la web y él te la
devuelve corregida, también tiene opciones para mostrarte los errores que
tenía la página.
Por último mencionaré otra aplicación interesante, en este caso un Add-on de
Firefox llamado HTML Validator http://users.skynet.be/mgueury/mozilla/ .
Este Add-on lo que hace es usar la tecnología del w3c para ver si la página que
estás visitando tiene o no errores y la tecnología de Tidy, para corregir esos
errores.
Además te los clasifica en 3 categorías, dependiendo de si Tidy puede
corregirlos o no,o si son sólo warnings.
Cómo vemos Tidy al igual que los demás no puede corregir todos los errores
que devuelve el validador.
18
Tipología de errores
Según su página web (http://validator.w3.org/docs/errors.html) el validador
detecta hasta 447 errores.
Empezaremos destacando los errores más comunes que hay en las páginas
hechas por alumnos de la UR y alojadas en https://belenus.unirioja.es/
Elegimos al azar 50 páginas de alumnos, 28 de ellas estaban validadas y las
otras 8 tenían errores que no eran de HTML 4.01 Strict.
Los errores encontrados en las páginas sin validar son:
Alumno Error (Código error)
1
1.(65)El tipo de documento no permite el elemento X aquí;falta una
etiqueta de inicio Y
2. (68)Etiqueta de cierre de X omitido, pero su declaración no lo
permite
2
1.(65)El tipo de documento no permite el elemento X aquí;falta una
etiqueta de inicio Y
3
1. (68) Etiqueta de cierre de X omitido, pero su declaración no lo
permite
4
1. (79)Etiqueta de cierre de X elemento que no está abierto
5
1. (68) Etiqueta de cierre de X omitido, pero su declaración no lo
permite
2. (79) Etiqueta de cierre de X elemento que no está abierto
6
1. (108) No hay ningún atributo X
2. (79) Etiqueta de cierre de X elemento que no está abierto
7
1. Entidad X no está definida y no hay ninguna entidad por defecto
8
1. (108) No hay ningún atributo X
1. (65)El tipo de documento no permite el elemento X aquí;falta una
etiqueta de inicio Y
9
10
11
12
13
14
1. (68)Etiqueta de cierre de X omitido, pero su declaración no lo
permite
2. (79)Etiqueta de cierre de X elemento que no está abierto
1. (25)Entidad X no está definida y no hay ninguna entidad por
defecto
1. (112)Doble especificación del atributo X
2. (73)Etiqueta final para X que no está terminado
3. (76)Elemento X indefinido
4. (108) No hay ningún atributo X
1. (65)El tipo de documento no permite el elemento X aquí;falta una
etiqueta de inicio Y
2. (79)Etiqueta de cierre de X elemento que no está abierto
1. (79)Etiqueta de cierre de X elemento que no está abierto
1. (68) Etiqueta de cierre de X omitido, pero su declaración no lo
permite
19
En resumen, los errores que más aparecen son:
1. Etiqueta de cierre de X elemento que no está abierto (6 veces)
El Validador encontró una etiqueta final del elemento X, pero ese
elemento no está abierto
2. Etiqueta de cierre de X omitido, pero su declaración no lo permite(5
veces)
Ocurre cuando no se cierra una etiqueta o cuando se utiliza algo que no
está permitido dentro de la etiqueta y el validador nos pide que cerremos
la etiqueta
3. El tipo de documento no permite el elemento X aquí; falta una etiqueta
de inicio Y (4)
El elemento no puede aparecer en el contexto en el que lo has puesto,
los demás elementos mencionados son los únicos que están permitidos
allí y pueden contener el elemento mencionado. Esto podría significar
que se necesita un elemento contenedor, o, posiblemente, de que te has
olvidado de cerrar un elemento anterior.
4. No hay ningún atributo X (3 veces)
Has usado el atributo mencionado anteriormente en tu documento, pero
el tipo de documento que estás usando no es compatible con ese
atributo para este elemento.
Clasificación de los errores
Del anterior estudio se puede sacar los 3 primeros tipos de errores:
Errores relacionados con las etiquetas:
Los que tienen que ver con fallos en las etiquetas, porque sobran, faltan o
están mal definidas.
Errores relacionados con los atributos:
Los que tienen que ver con fallos en los atributos, mala especificación,
duplicados, etc..
Errores relacionados con los elementos:
Los que tienen que ver con fallos en los elementos, mala definición, duplicados,
etc..
De entre los demás errores, he podido distinguir errores relaciones con el tipo
de documento, con las secciones marcadas, sobre referencias y links, sobre
comentarios…
Los errores demasiado específicos que no pueden ser introducidos en alguna
de las categorías anteriores irán en el tipo Errores especiales.
20
Errores corregibles
Los errores que nuestra aplicación podrá corregir serán los que tengan que ver
con fallos en las etiquetas.
De entre ellos, nuestra aplicación podrá corregir:
28: Comentario sin terminar
Ocurre cuando no se cierran los comentarios y puede que todo el código
siguiente quede como comentario.
Ej: <!-- Comentario >
La aplicación pondrá al final de la línea donde está el comentario la etiqueta de
cierre “-->”
38: Falta delimitador de cierre
Ocurre cuando no se ha cerrado una comilla o comilla doble.
Ej: “Ejemplo
La aplicación tendrá que añadir unas comillas al finalizar la palabra donde se
encuentren las comillas sin cierre: “Ejemplo”
42: Declaración desconocida de un tipo X
Ocurre cuando se usa una mala sintaxis para los comentarios
Ej: <! Comentario!>
La aplicación tendrá que añadir al principio y al final del texto donde esté el
error los correctos caracteres para hacer comentarios:< !-- Comentario! > -->
68: Etiqueta de cierre de X omitido, pero su declaración no lo permite
Ocurre cuando no se cierra una etiqueta o cuando se utiliza algo que no está
permitido dentro de la etiqueta y el validador nos pide que cerremos la etiqueta.
El siguiente mensaje, " start tag was here ", señala el caso particular de la
etiqueta en cuestión, el indicador de posición de los puntos apunta donde el
validador espera que hay que cerrar la etiqueta.
Ej:<a> Esto es un ejemplo
Depende del tipo de etiqueta sin cerrar el validador hará distintas cosas hasta
decidir donde colocar la etiqueta de cierre: <a> Esto es un ejemplo</a>
69: Etiqueta de inicio estaba aquí
Este no es un error, sino un puntero a la etiqueta inicial del elemento del error
anterior se refiere.
79: Etiqueta de cierre de X elemento que no está abierto
El Validador encontró una etiqueta final del elemento X, pero ese elemento no
está abierto
Ej: </a>
La aplicación eliminará la etiqueta de cierre.
21
Lista de requisitos
A continuación enumero la lista de requisitos que nuestro sistema tendrá que
ser capaz de cumplir:
1. El sistema será capaz de darle al usuario la capacidad de encontrar el
fichero en su ordenador.
2. El sistema será capaz de hacer una copia del fichero para mantener el
original intacto.
3. El sistema será capaz de pasar el fichero al validador W3C y analizar los
resultados.
4. El sistema será capaz de corregir los errores que están en la lista de
errores corregibles.
5. El sistema será capaz de informar al usuario de cualquier fallo que
hubiese en la ejecución.
6. El sistema será capaz de informar si no se ha podido corregir ningún
error
7. El sistema analizará ficheros html y htm.
8. El sistema dará la posibilidad de volverlo a corregir e informará si ya no
quedan errores.
22
Arquitectura Cliente-Servidor
De entre las diferentes arquitecturas, nuestro sistema va a usar la arquitectura
Cliente-Servidor.
A continuación copio una pequeña descripción de este tipo de Arquitectura
sacada de la Wikipedia (http://es.wikipedia.org/wiki/Cliente-servidor)
“La arquitectura cliente-servidor es un modelo de aplicación distribuida en el
que las tareas se reparten entre los proveedores de recursos o servicios,
llamados servidores, y los demandantes, llamados clientes. Un cliente realiza
peticiones a otro programa, el servidor, quien le da respuesta. Esta idea
también se puede aplicar a programas que se ejecutan sobre una sola
computadora, aunque es más ventajosa en un sistema
operativo multiusuario distribuido a través de una red de computadoras.
En esta arquitectura la capacidad de proceso está repartida entre los clientes y
los servidores, aunque son más importantes las ventajas de tipo organizativo
debidas a la centralización de la gestión de la información y la separación de
responsabilidades, lo que facilita y clarifica el diseño del sistema.
La separación entre cliente y servidor es una separación de tipo lógico, donde
el servidor no se ejecuta necesariamente sobre una sola máquina ni es
necesariamente un sólo programa. Los tipos específicos de servidores incluyen
los servidores web, los servidores de archivo, los servidores del correo, etc.
Mientras que sus propósitos varían de unos servicios a otros, la arquitectura
básica seguirá siendo la misma.
Una disposición muy común son los sistemas multicapa en los que el servidor
se descompone en diferentes programas que pueden ser ejecutados por
diferentes computadoras aumentando así el grado de distribución del sistema.
La arquitectura cliente-servidor sustituye a la arquitectura monolítica en la que
no hay distribución, tanto a nivel físico como a nivel lógico.”
En nuestro caso,el cliente será el usuario, que deberá introducir el fichero y
pedir que el sistema lo corrija. El sistema será el servidor que reciba la solicitud
del cliente y la procese.
Notar que a su vez el sistema hace de cliente del validador W3C (que sería el
servidor en ese escenario)
23
Diseño
Diagrama de Casos de Uso
Id
Descripción
Secuencia
Normal
Excepciones
A12: W3C
Manda el Documento al W3C y recoge los errores que tenga
1.Manda el documento al W3C
2.Recoge lo que el W3C devuelve
1.Si falla la conexión al w3c se informa al usuario
Id
Descripción
Secuencia
Normal
Excepciones
A1 :Seleccionar errores
Detecta los errores que puedes ser corregidos automáticamente
1.Va analizando cada línea de error y se queda con los que puede corregir
2.Devuelve los códigos de los errores corregibles y donde se encuentran
Id
Descripción
Secuencia
Normal
Excepciones
A2 : Corregir Error
Corrige el error
1.Corriege el error con el código recibido
Id
Descripción
Secuencia
Normal
Excepciones
A3: CopiaFichero
Hace una copia del fichero original.
1.Se hace una copia del fichero original con el mismo nombre añadiendo
“_Copia”
1.Si hay algún error en la ejecución se informa al usuario
1.Si hay algún error en la ejecución se informa al usuario
24
Id
Descripción
Secuencia
Normal
Excepciones
A: Analizar Documento
Pide un Documento al usuario y lo corrige haciendo una copia
1.Pide al usuario que introduzca un documento
2.Usa A3
3.Usa A12
5.Usa A1
5. Usa A2 hasta que no queden códigos de errores
1.Si el usuario no introduce un HTML ,no continua hasta que lo hace
2.
25
Diagrama de Actividad
El sistema manda al usuario introducir un documento y verifica que es HTML.
Crea la copia del documento para posibles fallos y trabaja con el original.
Manda el documento al W3C y recoge los resultados.
De entre los errores recibidos va corrigiendo todos los errores que puedan ser
corregidos hasta que no queden errores por corregir.
Vuelve a mandar el documento para ver cuántos errores tiene ahora.
El sistema dará la posibilidad de volver a corregir el fichero.
26
Diagrama de Clases
27
La clase Error y sus subclases
Lo primero en lo que pensé a la hora de hacer el diagrama de clases fue en la
clase Error. Era necesario tener una clase que supiese que pautas seguir para
corregir cada error.
En principio tenía planeado sólo hacer la clase Error y hacer tantos
corregirErrorX (con X el Id del error) como errores había, pero se complicaba
bastante el código y al final opté por usar herencia , haciendo el método
corregirError abstracto, por lo que la clase Error también.
Cada subclase ErrorX se encarga de implementar el método corregirError para
ese error X.
Tras analizar el código que me devolvía el W3C vi que lo que me hacía falta
para identificar cada error era el Id de ese error y la línea donde se había
detectado el error, por lo tanto os atributos de la clase Error son el id del error y
la línea.
El atributo línea es de tipo protected para que las subclases puedan acceder a
él.
La clase Resultados
Ahora que ya tenía los errores debía pensar en cómo obtenerlos, y esta es la
clase que se encarga de ello.
Su funcionalidad es conseguir mandar al w3c el archivo y con lo que nos
devuelve analizarlo y sacar los errores que teníamos.
El atributo resultado : double [][] es una matriz 2xN, con N el número de
errores .
En una columna de la matriz guardaremos el Id del error encontrado y en la
otra la línea en la que nos indica donde está el error.
El atributo numErrores es un entero con el número de errores encontrados.
Los métodos getFila y getId nos devuelve un double con la línea y el Id del
error del elemento que se encuentra en la posición que le pasamos como
argumento.
28
La clase GestorError
Ya tenemos los Errores y como solucionarlos y también los errores que tiene
nuestro documento, ahora hace falta otra clase que sea capaz de analizar
cuáles de esos errores somos capaces de corregir automáticamente y
corregirlos, esa es la clase GestorError.
Los atributos de la clase GestorError son un errores:Vector<Error> y
nomFichero.
El atributo errores es un Vector compuesto de elementos Error que lo crea el
constructor de la clase ,que tiene una llamada al constructor de la clase
Resultados y criba los Id de error que podemos corregir usando el método
ErrorCorregible.
Cuando hay un Id de un error corregible se crea un elemento ErrorX con X ese
Id y se añade al Vector errores.
El otro método importante de la clase es el método Corregir que corrige los
errores que contiene el atributo errores.
Pruebas
Haremos pruebas para comprobar que se cumplen todos y cada uno de los
requisitos:
Que el programa busca correctamente el fichero.
Que la copia del fichero se realiza correctamente.
Que el fichero se manda correctamente al W3C.
Comprobaremos si nos informa correctamente cuando no hay internet y si
introducimos un archivo no-html.
Pruebas con archivos que tengan que ser analizados más de una vez.
También haremos pruebas con páginas aleatorias de alumnos alojadas en
Belenus.
29
Implementación
Por las características del proyecto esta es la parte más costosa y difícil de
elaborar.
El mayor problema de la implementación ha sido interactuar con el validador
W3C, hasta tal punto que tuve que crear una clase intermedia llamada “Prueba”
para poder ir probando cómo funcionaban las demás clases hasta que al final
alcancé una solución.
Dividí el proyecto en tres paquetes, uno llamado errores ,que contiene los
errores y todo lo relacionado con ellos, otro llamado interfazGrafica que
contiene las ventanas gráficas con las que interactúa el usuario , y otro llamado
principal que es el que contiene la clase Principal con el método main.
30
El paquete errores
Este paquete contiene la clase Error y sus subclases ErrorX ,la clase
GestorError y la clase Resultados( Inicialmente la clase Prueba).
Las subclases de la clase error tienen en común que su constructor
simplemente llama al constructor de Error mediante la orden super.
También que todos corrigen el error copiando el fichero línea a línea hasta que
llegan a la línea donde está el error que cada clase hará lo que deba hacer.
El parámentro de entrada nomF es el archivo que hay que corregir.
31
La clase Error
package errores;
public abstract class Error {
protected double linea;
protected double columna;
private double id;
public Error (double id,double linea,double columna){
this.linea= linea;
this.id=id;
this.columna=columna;
}
public abstract void corregirError(String nomF);
public double getId(){
return this.id;
}
public double getLinea(){
return this.linea;
}
}
Como todos los errores van a tener los mismos atributos y en los únicos que
cambian es la manera en la que corrigen su error, decidí usar herencia.
Ésta es la superclase y tiene los atributos que nos harán falta para identificar
cada error.
Atributos:
El atributo línea es de tipo double y se declara protected para poder ser usado
por las subclases. Guarda la línea donde el validador nos ha dicho q se
encuentra el error.
El atributo Id nos devuelve el identificador de cada error (identificador basado
en los Id de cada error según este documento:
http://validator.w3.org/docs/errors.html )
Métodos:
El método corregirError(String nomF) es abstracto y cada subclase se
encargará de implementarlo según convenga a cada error.
La clase también tiene dos métodos get para acceder a sus dos atributos.
32
La clase Error28_53
Me di cuenta de que ambos errores se podrían corregir de la misma manera.
El validador cuando aparece uno de esos dos errores lanza a continuación un
mensaje de donde está el inicio del comentario que crea los errores.
Esta clase se encarga de ir donde nos dice el validador y cerrar la etiqueta de
comentario que está dando errores.
package errores;
import
import
import
import
import
import
java.io.BufferedReader;
java.io.BufferedWriter;
java.io.File;
java.io.FileReader;
java.io.FileWriter;
java.io.IOException;
public class Error28_53 extends Error{
public Error28_53(double id, double linea,double columna) {
super(id, linea,columna);
}
public void corregirError(String nomF){
//Vamos a reescribir el fichero y en la fila donde está el
error añadimos al final "-->"
try {
int i =1;
File inFile = new File(nomF);
File outFile = new
File(GestorError.getNombreFichero());
FileReader in = new FileReader(inFile);
FileWriter out = new FileWriter(outFile);
BufferedReader br = new BufferedReader(in);
BufferedWriter bw = new BufferedWriter(out);
for (String line; ((line = br.readLine()) != null);)
{
if(i==this.linea)
{bw.write(line+"-->"+"\r"+"\n");}
else{
bw.write(line+"\r"+"\n");}
i++;
}
33
br.close();
bw.close();
} catch(IOException e) {
System.err.println("Hubo un error de
entrada/salida");
}
}
}
En este caso lo que hacemos es copiar el fichero línea a línea y en .la línea
donde nos ha indicado el validador que está el comentario abierto ponemos al
final “-->” para cerrar el comentario.
34
La clase Error42
Este es otro error que tiene que ver con los comentarios.
Aparece cuando un comentario empieza de una forma inválida.
Tras hacer unas pruebas me di cuenta de que aparecía cuando el comentario
empezaba por <!comentario…
package errores;
import
import
import
import
import
import
java.io.BufferedReader;
java.io.BufferedWriter;
java.io.File;
java.io.FileReader;
java.io.FileWriter;
java.io.IOException;
public class Error42 extends Error {
public Error42(double id, double linea,double columna) {
super(id, linea,columna);
}
public void corregirError(String nomF) {
//Este error se da cuando aparece un comentario comenzando
de esta forma <!c..
//Buscamos el <! y añadimos -- y al final de la linea -->
int i =1;
try{
File inFile = new File(nomF);
File outFile = new
File(GestorError.getNombreFichero());
FileReader in = new FileReader(inFile);
FileWriter out = new FileWriter(outFile);
BufferedReader br = new BufferedReader(in);
BufferedWriter bw = new BufferedWriter(out);
for (String line; ((line = br.readLine()) != null);)
{ if(i==this.linea)
{
int aux=line.lastIndexOf("<!");
int j;
for(j=0;j<line.length();j++)
{bw.write(line.substring(j, j+1));
if(j==aux+1)
{bw.write("--");}
}
bw.write("\r"+"\n");
}
else{bw.write(line+"\r"+"\n");}
i++;
}
br.close();
35
bw.close();
} catch(IOException e) {
System.err.println("Hubo un error de entrada/salida");
}
}
}
Copiamos las líneas normalmente y lo que hacemos cuando estamos en la
línea es encontrar el “<!” y copiar caracter a carácter y cuando estemos tras el
“<!” añadimos “--“ ,de tal forma que quedará “<!--“.
También añadimos el final de comentario al final de la línea “-->” en caso de
que no lo tuviese
36
La clase Error68
Este es el error más complejo que corrige el GeneradorHTML.
El error ocurre cuando el validador detecta que hay una etiqueta sin cierre y te
manda a donde está la etiqueta de inicio.
Lo que haremos será cerrar la etiqueta abierta.
package errores;
import
import
import
import
import
import
java.io.BufferedReader;
java.io.BufferedWriter;
java.io.File;
java.io.FileReader;
java.io.FileWriter;
java.io.IOException;
public class Error68 extends Error {
public Error68(double id, double linea,double columna) {
super(id, linea, columna);
}
public void corregirError(String nomF){
int i =1;
try{
File inFile = new File(nomF);
File outFile = new File(GestorError.getNombreFichero());
FileReader in = new FileReader(inFile);
FileWriter out = new FileWriter(outFile);
BufferedReader br = new BufferedReader(in);
BufferedWriter bw = new BufferedWriter(out);
for (String line; ((line = br.readLine()) != null);)
{
//Vamos a la linea del error y buscamos el primer < y
copiamos lo que haya hasta el > o el primer espacio
if(i==this.linea)
{
String etiqueta;
if(line.indexOf(" ", 1+(int)
this.columna)<line.indexOf(">", 1+(int) this.columna))
{etiqueta =line.substring((int) this.columna,line.indexOf("
", (int) this.columna));}
else {etiqueta =line.substring((int)
this.columna,line.indexOf(">", (int) this.columna));}
//Si el validador nos manda a una etiqueta ol o ul pasará a
las siguientes lineas hasta que lo primero q encuentre
//no sea un <li y entonces cerrará la etiqueta
if((etiqueta.equalsIgnoreCase("ol"))
||(etiqueta.equalsIgnoreCase("ul")))
{ bw.write(line+"\r"+"\n");
line = br.readLine();
while(line.contains("<li"))
{bw.write(line+"\r"+"\n");
line = br.readLine();
}
if(etiqueta.equalsIgnoreCase("ol"))
{bw.write("</ol>"+line+"\r"+"\n");}
37
else{bw.write("</ul>"+line+"\r"+"\n");}
}// fin del caso ol,ul
else{
if(etiqueta.equalsIgnoreCase("dl"))
{ bw.write(line+"\r"+"\n");
line = br.readLine();
while(line.contains("<dt")||line.contains("<dd"))
{bw.write(line+"\r"+"\n");
line = br.readLine();
}
bw.write("</dl>"+line+"\r"+"\n");
}//fin del caso dl
else{
//cerramos la etiqueta antes del próximo < en caso
de que exista
if(line.indexOf("<",1+(int) this.columna)!=-1)
{bw.write(line.substring(0,line.indexOf("<",1+(int)
this.columna))+"</"+etiqueta+">"+line.substring(line.indexOf("<",1+(in
t) this.columna))+"\r"+"\n");}
else{ bw.write(line+"</"+etiqueta+">"+"\r"+"\n");}
}//en caso de que falle una etiqueta que no tenga que ver
con listas
}
}//fin del caso que estemos en la linea
else{bw.write(line+"\r"+"\n");}
i++;
}//fin del fichero
br.close();
bw.close();
} catch(IOException e) {
System.err.println("Hubo un error de
entrada/salida");
}
}
}
Está dividido en tres casos, primero identificamos que etiqueta es la abierta,si
la etiqueta abierta es de declarar listas con <ol> ó <ul> , para evitar
desencadenar más errores las cerraremos cuando no haya más etiquetas <li>.
Lo mismo ocurre en el caso de que sea una lista <dl> que la cerraremos
cuando se acaben los <dt> y <dd>
38
La clase Error65_66
Este error aparece cuando hay un elemento que por el contexto no puede estar
ahí, y que falta un contenedor para contener a ese objeto.
package errores;
import
import
import
import
import
import
java.io.BufferedReader;
java.io.BufferedWriter;
java.io.File;
java.io.FileReader;
java.io.FileWriter;
java.io.IOException;
public class Error65_66 extends Error {
public Error65_66(double id, double linea,double columna) {
super(id, linea, columna);
}
public void corregirError(String nomF){
int i =1;
int abiertas =0;
int abierto=0;
try{
File inFile = new File(nomF);
File outFile = new File(GestorError.getNombreFichero());
FileReader in = new FileReader(inFile);
FileWriter out = new FileWriter(outFile);
BufferedReader br = new BufferedReader(in);
BufferedWriter bw = new BufferedWriter(out);
int tipo =0;
for (String line; ((line = br.readLine()) != null);)
{
//Vamos a la linea del error y buscamos el primer <
antes de donde nos indico el w3c
if(i==this.linea)
{
int aux;
switch(tipo){
case 1:
aux=line.lastIndexOf("<",(int) this.columna-1);
bw.write(line.substring(0,aux)+"<li>"+line.substring(aux)+"\r"+"\n");
break;
case 2:
aux=line.lastIndexOf("<",(int) this.columna-1);
bw.write(line.substring(0,aux)+"<dt>"+line.substring(aux)+"\r"+"
\n");
break;
default:
bw.write(line+"\r"+"\n");
}
}//fin del caso que estemos en la linea
else{bw.write(line+"\r"+"\n");}
39
//Miramos cual es la ultima etiqueta antes de la linea para
distinguir casos
if(line.contains("<ol")||line.contains("<ul"))
{
if(tipo!=1)
{tipo=1;}
abiertas=abiertas+1;
}
if(line.contains("<dl"))
{if(tipo!=2)
{ tipo=2;}
abierto=abierto+1;
}
if(line.contains("</ol")||line.contains("</ul"))
{abiertas=abiertas-1;
if((abiertas==0)&&(abierto==0))
{tipo=0;}
if((tipo==1)&&(abierto!=0))
{tipo=2;}
}
if(line.contains("</dl"))
{abierto=abierto-1;
if((abiertas==0)&&(abierto==0))
{tipo=0;}
if((tipo==2)&&(abiertas!=0))
{tipo=1;}
}
i++;
}//fin del fichero
br.close();
bw.close();
} catch(IOException e) {
System.err.println("Hubo un error de
entrada/salida");
}
}
}
Este error no estaba planeado corregirlo al principio pero visto su similitud con
el Error68 he reutilizado gran parte del código.
Primero identificamos que etiqueta es la abierta, si la etiqueta abierta es de
declarar listas con <ol> ó <ul> , añadiremos una etiqueta contenedor <li>.
Lo mismo ocurre en el caso de que sea una lista <dl> cuando nos encontramos
<dt> y <dd>
40
La clase Error79
Este error ocurre cuando hay una etiqueta de cierre sin que haya uno de inicio.
Lo que haremos será eliminar esa etiqueta.
package errores;
import
import
import
import
import
import
java.io.BufferedReader;
java.io.BufferedWriter;
java.io.File;
java.io.FileReader;
java.io.FileWriter;
java.io.IOException;
public class Error79 extends Error {
public Error79(double id, double linea,double columna) {
super(id, linea,columna);
}
public void corregirError(String nomF){
int i =1;
try{
File inFile = new File(nomF);
File outFile = new
File(GestorError.getNombreFichero());
FileReader in = new FileReader(inFile);
FileWriter out = new FileWriter(outFile);
BufferedReader br = new BufferedReader(in);
BufferedWriter bw = new BufferedWriter(out);
for (String line; ((line = br.readLine()) != null);)
{
//Vamos a la linea del error y el primer </ y lo
eliminamos
if(i==this.linea)
{
int inicio=line.lastIndexOf("</",(int) this.columna);
bw.write(line.substring(0, inicio));
bw.write(line.substring((int)
this.columna,line.length())+"\r"+"\n");
}
else{bw.write(line+"\r"+"\n");}
i++;
}//fin del fichero
br.close();
bw.close();
} catch(IOException e) {
System.err.println("Hubo un error de
entrada/salida");}}
}
Lo que hacemos es en la línea donde está el error eliminar la última etiqueta de
cierre que encontremos.
41
La clase GestorError
package errores;
import
import
import
import
import
java.io.File;
java.io.FileInputStream;
java.io.FileOutputStream;
java.io.IOException;
java.util.*;
public class GestorError {
private static Vector<Error> errores ;
private static String nomFichero;
private static boolean errorescorregibles = true;
private static boolean puedo;
private static boolean exito;
public static double num_errores=0; //numero errores corregibles
public static double vuelta = 0;
public GestorError (String nomF)
{
nomFichero = nomF;
w3c();
}// Fin GestorError()
public boolean puedoCorregir(){
return errorescorregibles;
}
public boolean puedo(){
return puedo;
}
public boolean exito(){
return exito;
}
public double getNumero_errores(){
return num_errores;
}
public void Corregir(){
//Lo duplicamos sólo la primera vez
vuelta = vuelta+1;
if(vuelta==1){
DuplicarFichero(nomFichero,nomFichero.substring(0,nomFichero.len
gth()-5) + "_copia.html");
}
//El fichero auxiliar se llamará como el otro con un (2),
para ellos tomamos el nombre
//y le quitamos los 5 último caracteres ".html" y le
añadimos su nuevo final
String nomD= nomFichero.substring(0,nomFichero.length()-5)
+ "(2).html";
42
int i =0;
while(i<errores.size()){
DuplicarFichero(nomFichero,nomD);
errores.get(i).corregirError(nomD);
i=i+1;
}
BorrarFichero(nomD);
errores.clear();
num_errores=0;
w3c();
}
public static void DuplicarFichero(String nomF, String
nomD) {
try {
File inFile = new File(nomF);
File outFile = new File(nomD);
FileInputStream in = new
FileInputStream(inFile);
FileOutputStream out = new
FileOutputStream(outFile);
int c;
while( (c = in.read() ) != -1)
out.write(c);
in.close();
out.close();
} catch(IOException e) {
System.err.println("Hubo un error de
entrada/salida!!!");
}
}
public static void BorrarFichero(String nomD){
File fichero = new File(nomD);
if (fichero.delete()==false)
{ System.out.println("Error al borrar el fichero
temporal");}
}
public static String getNombreFichero() {
return nomFichero;
}
public static void w3c (){
Resultados r = new Resultados(nomFichero);
puedo= r.getPuedo();
exito = r.getExito();
43
// Si no ha habido errores, y el archivo no estaba ya
limpio
if((puedo==true)&&(exito==false))
{
errores = new
Vector<Error>((int)r.numeroResultados());
//si el error es corregigle lo añade al gestor de
Errores y se crea un vector con todos los errores
//En caso de que no haya ninguno corregible
errorescorregibles se pondrá a false
double noC=0;
for(int i = 0 ; i< r.numeroResultados();i++)
{
int aux=(int)r.getId(i);
switch(aux){
case 28:
errores.add(new
Error28_53(r.getId(i),r.getFila(i),r.getColumna(i)));
break;
case 53:
errores.add(new
Error28_53(r.getId(i),r.getFila(i),r.getColumna(i)));
break;
case 42:
errores.add(new
Error42(r.getId(i),r.getFila(i),r.getColumna(i)));
break;
case 65:
errores.add( new
Error65_66(r.getId(i),r.getFila(i),r.getColumna(i)));
break;
case 66:
errores.add( new
Error65_66(r.getId(i),r.getFila(i),r.getColumna(i)));
break;
case 68:
errores.add( new
Error68(r.getId(i),r.getFila(i),r.getColumna(i)));
break;
case 79:
errores.add(new
Error79(r.getId(i),r.getFila(i),r.getColumna(i)));
break;
default:
noC=noC+1;
break;
}
}//Fin for
if(noC==r.numeroResultados())
{
errorescorregibles=false;
}
44
num_errores = r.numeroResultados()- noC;
}// fin de puedo==true ó exito=false
}
}
Atributos:
private Vector<Error> errores
Es un vector con los errores que podemos corregir del fichero.
private static String nomFichero
Aquí es donde guardamos el nombre del fichero html
private boolean errorescorregibles = true
Es un boolean que nos va a indicar si el fichero tiene algún error corregible por
nuestra aplicación.Se inicia con valor verdadero.
private boolean puedo
Este Boolean lo recogemos de la clase Resultados y nos dice si el w3c ha
podido analizar el documento.
private boolean exito
Este Boolean lo recogemos de la clase Resultados y nos dice si el w3c ha
declarado el documento válido.
public static double num_errores=0;
Este double nos indica el número de errores que quedan y están entre
los corregibles
Métodos:
El constructor de la clase simplemente llama al método w3c()-.
El método más importante de esta clase es el w3c.
Se encarga de llamar a la Clase Resultados, creando un objeto Resultados, y
analizarlo viendo los Ids de los errores que contiene.
Si tiene un Id reconocido por la aplicación crea un objeto de ese tipo de error y
se añadirá al Vector errores, que lo iniciamos con capacidad para que
almacene tantos errores como errores ha localizado Resultados.
En caso de que no reconozca ningún error pondrá errorescorregibles a false.
Tenemos también el método Corregir() , que se encarga de corregir cada error
que contiene el Vector errores.
Este método se apoya en los métodos DuplicarFichero y BorrarFichero.
45
Empezamos duplicando el fichero por seguridad, el fichero quedará como
nombre_copia.html.
Notar que sólo se duplicará la primera vez que corrijamos.
Mientras queden errores hacemos una copia del archivo (nombre(2).html) y esa
copia se la pasamos a corregirFichero , y éste sobreescribe nombre.html y nos
lo deja corregido y borra nombre(2).html
El método getNombreFichero es el que usa corregirFichero para saber donde
guardar el resultado.
Para crear DuplicarFichero y BorrarFichero me he apoyado en búsquedas en
google.
A parte tiene los métodos get para acceder a sus atributos.
46
La clase Resultados
Ésta es, sin duda, la clase más difícil de la aplicación
Nosotros lo que utilizaremos será la segunda opción a la hora de validar: pasar
un fichero que tengamos en nuestro equipo y que el w3c lo analice.
Este ha sido el gran problema del proyecto y que ha creado grandes retrasos
en el mismo.
HTML tiene dos formas para hacer FORMs (formularios para recopilar
información, en nuestro caso para que les digas la ruta del fichero), el método
GET y el método POST.
El método POST tiene una forma fácil de ser utilizado ya que con añadir al final
de la URL el nombre de los parámetros tras un “?” , por ejemplo:
http://validator.w3.org/check?uri=www.google.es&charset=%28detect+automati
cally%29&doctype=Inline&group=0&user-agent=W3C_Validator%2F1.3
El validador, sólo usa este tipo de FORM en la opción de pasarle una URL.
El método GET no tiene ninguna forma de ser usado así de manera fácil cómo
el anterior, ni tampoco ninguna opción de JAVA, el lenguaje que se usa para el
proyecto, para pasar FORMs y obtener el resultado.
El validador usa este tipo de FORM en la opción que nosotros usamos, la de
Pasar la ruta de un fichero, así que aquí ha estado el gran problema del
proyecto.
En un inicio, al no encontrar manera de usar este tipo de FORM lo que hice fue,
mediante FTP, subir el archivo a un servidor gratuito y eso me daba una URL y
entonces pasaba la URL del modo fácil mediante la primera opción del
validador que si usa el método POST.
Tras hablarlo con el director acordamos encontrar una solución mejor ya que el
hecho de subirlo al servidor creaba muchos problemas a la hora de leer el
documento y retrasaba la ejecución de la aplicación.
Al final, gracias a la ayuda del Director del Proyecto llegamos a una solución,
llamar al comando “curl” desde Java de la siguiente forma:
curl -F uploaded_file=@/../archivo.html
http://validator.w3.org/check
Esto nos devuelve el código html de lo que el validador ha analizado en nuestro
fichero, y que más tarde parsearemos para recoger los errores.
El comando “curl” no está incluido en Windows, así que tuve que descargarlo e
incluirlo en la carpeta del proyecto para que la función “exec” de JAVA lo
reconociese.
package errores;
47
import
import
import
import
import
java.io.BufferedReader;
java.io.IOException;
java.io.InputStream;
java.io.InputStreamReader;
java.net.*;
public class Resultados {
//Iniciamos la matriz resultado
private double [][] resultado = new double[3][100] ;
private int numErrores = 0;
private boolean puedo = true;
private boolean exito = false;
public Resultados(String nomF) {
int n =100;
for(int a=0; a<3; a++){
for(int b=0; b<n; b++){
this.resultado[a][b]=0.0;
}
}
int i=0;
int j,inicio,fin;
try{
// Se lanza el ejecutable.
String ruta
="uploaded_file=@"+nomF.substring(1+nomF.indexOf(":"));
String [] cmd = {"curl","F",ruta,"validator.w3.org/check"};
Process p=Runtime.getRuntime().exec (cmd);
// Se obtiene el stream de salida del programa
InputStream is = p.getInputStream();
/* Se prepara un bufferedReader para poder leer la salida
más comodamente. */
BufferedReader reader = new BufferedReader (new
InputStreamReader (is));
// Se lee la primera linea
String line = reader.readLine();
// Mientras se haya leido alguna linea
while ((line!=null)&&(puedo==true)&&(exito==false))
{
if(line.contains("Sorry! This document cannot be
checked."))
{
puedo = false;
}
if(line.contains("Congratulations"))
48
{
exito = true;
}
if(line.contains("msg_err")){
/*Si la linea contiene "msg_err" es que estamos en
la parte del código donde esta el error de la siguiente forma:
<li class="msg_err"> y ahora buscamos el lugar del
error y el id error en las siguiente lineas
El lugar está tres lineas mas abajo y con codigo ej:
<em>Line 9,
El id del error está 6 lineas más abajo ej:
href="feedback.html?uri=;errmsg_id=68#errormsg" */
for(j=1;j<=3;j++)
{line = reader.readLine();}
inicio = line.indexOf("Line");
fin = line.indexOf(",");
this.resultado[1][i]=Double.valueOf(line.substring(inicio+5,fin));
line= reader.readLine();
inicio = line.indexOf("Column");
fin = line.indexOf("<");
this.resultado[2][i]=Double.valueOf(line.substring(inicio+7,fin));
for(j=1;j<=5;j++)
{line = reader.readLine();}
inicio = line.indexOf("id=");
fin = line.indexOf("#");
this.resultado[0][i]=Double.valueOf(line.substring(inicio+3,fin));
//En alguno de los errores la línea donde comienza el
error te la da en un mensaje
if((this.resultado[0][i]==28)||(this.resultado[0][i]==53)||(this
.resultado[0][i]==68)){
while(line.contains("msg_info")==false)
{line=reader.readLine();}
for(j=1;j<=3;j++)
{line = reader.readLine();}
inicio = line.indexOf("Line");
fin = line.indexOf(",");
this.resultado[1][i]=Double.valueOf(line.substring(inicio+5,fin));
line= reader.readLine();
inicio = line.indexOf("Column");
fin = line.indexOf("<");
this.resultado[2][i]=Double.valueOf(line.substring(inicio+7,fin));
}//fin de encontrar linea en ciertos errores
i=i+1;
//redimensionamos el vector en caso de que haya
demasiados errores
if(i==n)
49
{double [][] aux=resultado.clone();
resultado= new double[3][2*n] ;
for(int a=0; a<3; a++){
for(int b=0; b<n; b++){
this.resultado[a][b]=aux[a][b];
}
}
for(int a=0; a<3; a++){
for(int b=n; b<2*n; b++){
this.resultado[a][b]=0.0;
}
}
n=2*n;
}//fin redimension
}//fin if encontró error
// se lee la siguiente.
line = reader.readLine();
}// se ha acabado el fichero
reader.close();
this.numErrores= i;
}catch(MalformedURLException m)
{
puedo = false;
System.err.println("Hubo un error con la URL");
}
catch(IOException e) {
puedo = false;
System.err.println("Hubo un error de
entrada/salida");
}
} //fin de Resultados()
public double getFila(int i){
return this.resultado[1][i];
}
public double getColumna(int i){
return this.resultado[2][i];
}
public double getId(int i){
return this.resultado[0][i];
}
public double numeroResultados(){
return this.numErrores;
}
public boolean getPuedo(){
return puedo;
}
public boolean getExito(){
return exito;
}}
50
Atributos:
private double [][] resultado = new double[2][100]
Es una matriz doble que le daremos un tamaño máximo de 2x100.
En las posiciones [0][n] se guardaran los Ids que vayamos encontrando y en las
[1][n] la línea donde esta.
private int numErrores = 0
En esta variable guardamos el número de errores encontrados.
private boolean puedo = true;
private boolean exito = false;
En estas variables guardamos booleanos para darnos cuenta de si el W3C no
ha podido corregir el fichero o de si el fichero esta corregido respectivamente.
Sólo cambian de valor en el caso de que en el fichero devuelto encontremos:
if(line.contains("Sorry! This document cannot be checked."))
{ puedo = false; }
if(line.contains("Congratulations"))
{ exito = true; }
Métodos:
El constructor de la clase es el que se encarga de mandar el documento que
recibe como parámetro al w3c y recoger los resultados.
Primero inicia la matriz resultado poniendo los valores a 0.
Luego se prepara para mandar el fichero mediante curl , para ellos prepara las
opciones del curl
Esta preparación es debida a que si buscamos el fichero visualmente en vez de
introducir nosotros la ruta (ver el paquete interfazGrafica) nos devuelve la ruta
de la forma c:\...\nombre.html y curl funciona introduciendo la ruta como
uploaded_file=@…
Ahora llamamos a Process p=Runtime.getRuntime().exec (cmd);
Abrimos los Streams y creamos BufferedReader para poder leer lo que nos ha
devuelto el curl.
Analizamos el código devuelto por esa URL línea a línea, si hay error nos
encontraremos la etiqueta <li class=”msg_err”>
Una vez descubierto el error el w3C se comporta siempre igual, tres líneas
debajo nos indica la línea donde se ha producido el error,la guardamos, y 6
líneas más abajo nos encontramos el código de ese error que también nos lo
guardamos.
51
En algunos errores (que ya sabemos cuales son) nos sale otra etiqueta con
msg_info , así que en esos casos buscamos la etiqueta y sustituimos el valor
que habíamos guardado para la línea por este nuevo.
A parte de estos dos métodos tenemos 5 métodos get que nos sirven para
acceder a los atributos de la clase.
52
El paquete interfazGráfica
Este paquete incluye 6 clases, la clase InferfazGráfica que es lo que vemos al
ejecutar el programa y otras 5 que son para informar al usuario.
Son clases java de tipo Visual Class, heredan de JFrame que tienen un
contenedor JPanel sin ningún layout (para poder poner los elementos donde
quiera)
53
La clase InterfazGrafica
package interfazGrafica;
import errores.*;
import java.awt.BorderLayout;
import
import
import
import
import
import
import
javax.swing.JFileChooser;
javax.swing.JPanel;
javax.swing.JFrame;
java.awt.Dimension;
javax.swing.JButton;
java.awt.Rectangle;
java.io.File;
import javax.swing.JTextField;
import javax.swing.JLabel;
public class InterfazGrafica extends JFrame
private
private
private
private
private
private
private
{
static final long serialVersionUID = 1L;
JPanel jContentPane = null;
JPanel Cuerpo = null;
JButton Analizar = null;
JTextField nombreFichero = null;
JLabel informacion = null;
JButton buscar = null;
/**
* This is the default constructor
*/
public InterfazGrafica() {
super();
initialize();
}
/**
* This method initializes this
*
* @return void
*/
private void initialize() {
this.setSize(new Dimension(400, 250));
this.setContentPane(getJContentPane());
this.setTitle("Generador HTML");
this.setVisible(true);
}
/**
* This method initializes jContentPane
*
* @return javax.swing.JPanel
*/
private JPanel getJContentPane() {
if (jContentPane == null) {
jContentPane = new JPanel();
jContentPane.setLayout(new BorderLayout());
jContentPane.add(getCuerpo(), BorderLayout.CENTER);
}
54
return jContentPane;
}
/**
* This method initializes Cuerpo
*
* @return javax.swing.JPanel
*/
private JPanel getCuerpo() {
if (Cuerpo == null) {
informacion = new JLabel();
informacion.setBounds(new Rectangle(32, 42, 247,
25));
informacion.setText("Introduce la dirección del
fichero ");
Cuerpo = new JPanel();
Cuerpo.setLayout(null);
Cuerpo.add(getAnalizar(), null);
Cuerpo.add(getNombreFichero(), null);
Cuerpo.add(informacion, null);
Cuerpo.add(getBuscar(), null);
}
return Cuerpo;
}
/**
* This method initializes Analizar
*
* @return javax.swing.JButton
*/
private JButton getAnalizar() {
if (Analizar == null) {
Analizar = new JButton();
Analizar.setBounds(new Rectangle(285, 138, 83, 28));
Analizar.setText("Analizar");
Analizar.addActionListener(new
java.awt.event.ActionListener() {
public void
actionPerformed(java.awt.event.ActionEvent e) {
//Primero vemos si es del tipo de archivo que
reconocemos
if((nombreFichero.getText().contains(".html"))||(nombreFichero.getText
().contains(".htm")) )
{//Creamos un Gestor Error con ese fichero
GestorError GE = new
GestorError(nombreFichero.getText());
//Si puedo== false, entonces el w3c no puede
analizarlo por un error
if(GE.puedo()==false)
{ErrorW3C fallo = new ErrorW3C();
fallo.setBounds(new Rectangle(50, 50,300, 162));
}
else{
//Si el archivo no contenia errores
exito==true
if(GE.exito()==true)
{SinError se = new SinError();
se.setBounds(new Rectangle(50, 50,300, 157));}
else{
//Si alguno de los errores son
corregibles por nosotros
55
if(GE.puedoCorregir())
{//Corregimos el archivo
GE.Corregir();
//Ahora iniciamos Éxito sabiendo
el número de errores que nos quedan por corregir
Exito ex = new Exito(GE.getNumero_errores(),GE);
ex.setBounds(new Rectangle(50, 50,400, 250));
}
else{
NoCorregibles nc = new NoCorregibles();
nc.setBounds(new Rectangle(50, 50,300, 150));
}
}
}
}//fin if fichero valido
else{Fallo f = new Fallo();
f.setBounds(new Rectangle(50, 50,300, 128));}
}
});
}
return Analizar;
}
/**
* This method initializes nombreFichero
*
* @return javax.swing.JTextField
*/
private JTextField getNombreFichero() {
if (nombreFichero == null) {
nombreFichero = new JTextField();
nombreFichero.setBounds(new Rectangle(29, 72, 250, 19));
}
return nombreFichero;
}
/**
* This method initializes buscar
*
* @return javax.swing.JButton
*/
private JButton getBuscar() {
if (buscar == null) {
buscar = new JButton();
buscar.setBounds(new Rectangle(289, 65, 76, 32));
buscar.setText("Buscar");
buscar.addActionListener(new
java.awt.event.ActionListener() {
public void
actionPerformed(java.awt.event.ActionEvent e) {
JFileChooser fc = new JFileChooser();
int returnVal =
fc.showOpenDialog(InterfazGrafica.this);
if (returnVal ==
JFileChooser.APPROVE_OPTION) {
56
File file = fc.getSelectedFile();
nombreFichero.setText(file.getAbsolutePath());
}
}});
}
return buscar;
}
}
//
@jve:decl-index=0:visual-constraint="41,10"
Al ser Visual Class ,Eclipse nos hace casi todo automáticamente según le
vamos indicando en el dibujo.
Cabe destacar el botón Analizar y Buscar que ambos tienen un ActionListener
(que están esperando a que los pulses para que algo ocurra)
En el caso del botón Analizar, primero se asegura que el fichero cuya ruta está
en el campo de texto nombreFichero es .html, en caso de que no sea lanzará
un objeto Fallo.
Si el fichero cumple lo anterior, crea un GestorError pasándole ese
nombreFichero como parámetro.
Ahora mira si el w3C ha podido analizar el documento, si no ha podido lanza un
objeto ErrorW3C.
En el caso de que si haya podido analizar el documento, mira a ver si el
documento estaba correcto.
Si el archivo está correcto crea un objeto SinError.
En caso contrario se asegura de que hay errores que corregir, en caso de que
los haya llama al método Corregir() de GestorError y tras eso lanza un objeto
Éxito.
En caso de que no los haya, lanza un objeto NoCorregibles.
El botón Buscar usamos la clase JFileChooser de Java para buscar un fichero
mediante pantalla y tras encontrarlo ponemos la ruta en el campo de texto
nombreFichero.
57
Clase Fallo
Estas ventanas salen cuando introducimos un fichero sin la extensión .html
package interfazGrafica;
import java.awt.BorderLayout;
import javax.swing.JPanel;
import javax.swing.JFrame;
import java.awt.Rectangle;
import javax.swing.JButton;
import javax.swing.JLabel;
public class Fallo extends JFrame {
private static final long serialVersionUID = 1L;
private JPanel jContentPane = null;
private JPanel jPanel = null;
private JButton Aceptar = null;
private JLabel jLabel = null;
private JLabel jLabel1 = null;
/**
* This is the default constructor
*/
public Fallo() {
super();
initialize();
}
/**
* This method initializes this
*
* @return void
*/
private void initialize() {
this.setSize(300, 128);
this.setContentPane(getJContentPane());
this.setTitle("Información");
this.setVisible(true); }
/**
* This method initializes jContentPane
*
* @return javax.swing.JPanel
*/
private JPanel getJContentPane() {
if (jContentPane == null) {
jContentPane = new JPanel();
jContentPane.setLayout(new BorderLayout());
jContentPane.add(getJPanel(), BorderLayout.CENTER);
}
return jContentPane;
}
/**
* This method initializes jPanel
*
* @return javax.swing.JPanel
*/
58
private JPanel getJPanel() {
if (jPanel == null) {
jLabel1 = new JLabel();
jLabel1.setBounds(new Rectangle(9, 40, 169, 29));
jLabel1.setText(" Introduzca un fichero válido");
jLabel = new JLabel();
jLabel.setBounds(new Rectangle(13, 8, 142, 29));
jLabel.setText("Error en el fichero.");
jPanel = new JPanel();
jPanel.setLayout(null);
jPanel.add(getAceptar(), null);
jPanel.add(jLabel, null);
jPanel.add(jLabel1, null);
}
return jPanel;
}
/**
* This method initializes Aceptar
*
* @return javax.swing.JButton
*/
private JButton getAceptar() {
if (Aceptar == null) {
Aceptar = new JButton();
Aceptar.setBounds(new Rectangle(182, 61, 83, 20));
Aceptar.setText("Aceptar");
Aceptar.addActionListener(new
java.awt.event.ActionListener() {
public void
actionPerformed(java.awt.event.ActionEvent e) {
Fallo.this.setVisible(false);
}
});
}
return Aceptar;
}
}
//
@jve:decl-index=0:visual-constraint="10,10"
Lo único destacable de la clase es que cuando pulsas el botón Aceptar tiene un
ActionListener que te cierra la ventana Fallo
59
La clase Éxito
Estas ventanas salen cuando se ha acabado de corregir y no ha surgido ningún
error.
Además te indica cuantos errores pueden ser corregidos tras la anterior
corrección y te da opción de volver a corregir o de salir.
package interfazGrafica;
import
import
import
import
import
import
java.awt.BorderLayout;
javax.swing.JPanel;
javax.swing.JFrame;
javax.swing.JLabel;
java.awt.Rectangle;
javax.swing.JButton;
import errores.GestorError;
public class Exito extends JFrame {
private
private
private
private
private
private
private
private
private
private
static final long serialVersionUID = 1L;
JPanel jContentPane = null;
JPanel jPanel = null;
JLabel jLabel = null;
JLabel jLabel1 = null;
JLabel jLabel2 = null;
JButton Continuar = null;
double num;
GestorError GE;
JButton Salir = null;
/**
* This is the default constructor
*/
public Exito(double num,GestorError Gestor) {
super();
this.num=num;
this.GE= Gestor;
initialize();
}
/**
* This method initializes this
*
* @return void
*/
private void initialize() {
this.setSize(331, 176);
this.setContentPane(getJContentPane());
this.setTitle("Corregido");
this.setVisible(true);
}
/**
* This method initializes jContentPane
*
* @return javax.swing.JPanel
60
*/
private JPanel getJContentPane() {
if (jContentPane == null) {
jContentPane = new JPanel();
jContentPane.setLayout(new BorderLayout());
jContentPane.add(getJPanel(), BorderLayout.CENTER);
}
return jContentPane;
}
/**
* This method initializes jPanel
*
* @return javax.swing.JPanel
*/
private JPanel getJPanel() {
if (jPanel == null) {
jLabel2 = new JLabel();
jLabel2.setBounds(new Rectangle(9, 60, 130, 22));
jLabel2.setText("tuarchivo_copia.html");
jLabel1 = new JLabel();
jLabel1.setBounds(new Rectangle(11, 39, 248, 16));
jLabel1.setText("Copia del archivo original guardada
como :");
jLabel = new JLabel();
jLabel.setBounds(new Rectangle(12, 5, 295, 29));
jLabel.setText("Archivo corregido con éxito.Quedan:
"+this.num+" errores");
jPanel = new JPanel();
jPanel.setLayout(null);
jPanel.add(jLabel, null);
jPanel.add(jLabel1, null);
jPanel.add(jLabel2, null);
jPanel.add(getContinuar(), null);
jPanel.add(getSalir(), null);
}
return jPanel;
}
/**
* This method initializes Continuar
*
* @return javax.swing.JButton
*/
private JButton getContinuar() {
if (Continuar == null) {
Continuar = new JButton();
Continuar.setText("Continuar");
Continuar.setBounds(new Rectangle(119, 98, 94, 28));
Continuar.addActionListener(new
java.awt.event.ActionListener() {
public void
actionPerformed(java.awt.event.ActionEvent e) {
if(GE.puedo()==false)
{ErrorW3C fallo = new ErrorW3C();
fallo.setBounds(new Rectangle(50,
50,300, 162));
61
}
else{
//Si no han quedado errores
if(GE.exito()==true)
{SinError se = new
SinError();
se.setBounds(new
Rectangle(50, 50,300, 157));}
else{if(GE.puedoCorregir())
{GE.Corregir();
Exito ex = new
Exito(GE.getNumero_errores(),GE);
ex.setBounds(new
Rectangle(50, 50,400, 250));
}
else{
NoCorregibles nc = new
NoCorregibles();
nc.setBounds(new
Rectangle(50, 50,300, 150));
}
}
}
}
});
}
return Continuar;
}
/**
* This method initializes Salir
*
* @return javax.swing.JButton
*/
private JButton getSalir() {
if (Salir == null) {
Salir = new JButton();
Salir.setBounds(new Rectangle(217, 98, 94, 28));
Salir.setText("Salir");
Salir.addActionListener(new
java.awt.event.ActionListener() {
public void
actionPerformed(java.awt.event.ActionEvent e) {
System.exit(0);
}
});
}
return Salir;
}
}
//
@jve:decl-index=0:visual-constraint="10,10"
62
La clase NoCorregible
Estas ventanas salen cuando la aplicación no reconoce ningún error de los que
ha encontrado el w3c.
package interfazGrafica;
import
import
import
import
import
import
import
java.awt.BorderLayout;
javax.swing.JPanel;
javax.swing.JFrame;
java.awt.GridBagLayout;
javax.swing.JLabel;
java.awt.Rectangle;
javax.swing.JButton;
public class NoCorregibles extends JFrame {
private
private
private
private
private
private
static final long serialVersionUID = 1L;
JPanel jContentPane = null;
JPanel jPanel = null;
JPanel jPanel1 = null;
JLabel jLabel = null;
JButton Aceptar = null;
/**
* This is the default constructor
*/
public NoCorregibles() {
super();
initialize();
}
/**
* This method initializes this
*
* @return void
*/
private void initialize() {
this.setSize(300,128);
this.setContentPane(getJContentPane());
this.setTitle("Información");
this.setVisible(true);
}
/**
* This method initializes jContentPane
*
* @return javax.swing.JPanel
*/
private JPanel getJContentPane() {
if (jContentPane == null) {
jContentPane = new JPanel();
jContentPane.setLayout(new BorderLayout());
jContentPane.add(getJPanel(), BorderLayout.SOUTH);
jContentPane.add(getJPanel1(), BorderLayout.CENTER);
}
return jContentPane;
}
/**
* This method initializes jPanel
*
63
* @return javax.swing.JPanel
*/
private JPanel getJPanel() {
if (jPanel == null) {
jPanel = new JPanel();
jPanel.setLayout(new GridBagLayout());
}
return jPanel;
}
/**
* This method initializes jPanel1
*
* @return javax.swing.JPanel
*/
private JPanel getJPanel1() {
if (jPanel1 == null) {
jLabel = new JLabel();
jLabel.setBounds(new Rectangle(11, 16, 244, 25));
jLabel.setText("No se encontraron errores
corregibles");
jPanel1 = new JPanel();
jPanel1.setLayout(null);
jPanel1.add(jLabel, null);
jPanel1.add(getAceptar(), null);
}
return jPanel1;
}
/**
* This method initializes Aceptar
*
* @return javax.swing.JButton
*/
private JButton getAceptar() {
if (Aceptar == null) {
Aceptar = new JButton();
Aceptar.setBounds(new Rectangle(160, 51, 91, 28));
Aceptar.setText("Aceptar");
Aceptar.addActionListener(new
java.awt.event.ActionListener() {
public void
actionPerformed(java.awt.event.ActionEvent e) {
System.exit(0);
}
});
}
return Aceptar;
}
}
//
@jve:decl-index=0:visual-constraint="13,20"
En este caso de nuevo el botón Aceptar cierra la aplicación.
64
Clase ErrorW3C
Estas ventanas salen cuando el w3C no puede analizar el documento.
package interfazGrafica;
import
import
import
import
import
javax.swing.JPanel;
javax.swing.JFrame;
javax.swing.JLabel;
java.awt.Rectangle;
javax.swing.JButton;
public class ErrorW3C extends JFrame {
private static final long serialVersionUID = 1L;
private JPanel jContentPane = null;
private JLabel jLabel = null;
private JButton jButton = null;
private JLabel jLabel1 = null;
/**
* This is the default constructor
*/
public ErrorW3C() {
super();
initialize();
}
/**
* This method initializes this
*
* @return void
*/
private void initialize() {
this.setSize(300, 162);
this.setContentPane(getJContentPane());
this.setTitle("Error");
this.setVisible(true);
}
/**
* This method initializes jContentPane
*
* @return javax.swing.JPanel
*/
private JPanel getJContentPane() {
if (jContentPane == null) {
jLabel1 = new JLabel();
jLabel1.setBounds(new Rectangle(7, 49, 146, 22));
jLabel1.setText("Pulsa Aceptar para salir ");
jLabel = new JLabel();
jLabel.setBounds(new Rectangle(7, 16, 221, 16));
jLabel.setText("El w3C no puede chekear el
archivo!!");
jContentPane = new JPanel();
jContentPane.setLayout(null);
jContentPane.add(jLabel, null);
jContentPane.add(getJButton(), null);
jContentPane.add(jLabel1, null);
}
return jContentPane;
65
}
/**
* This method initializes jButton
*
* @return javax.swing.JButton
*/
private JButton getJButton() {
if (jButton == null) {
jButton = new JButton();
jButton.setBounds(new Rectangle(166, 85, 96, 28));
jButton.setText("Aceptar");
jButton.addActionListener(new
java.awt.event.ActionListener() {
public void
actionPerformed(java.awt.event.ActionEvent e) {
System.exit(0);
}
});
}
return jButton;
}
}
//
@jve:decl-index=0:visual-constraint="10,10"
En este caso de nuevo el botón Aceptar cierra la aplicación.
66
La clase SinError
Estas ventanas salen cuando el w3C detecta que el documento es válido y no
contiene errores.
package interfazGrafica;
import
import
import
import
import
import
java.awt.BorderLayout;
javax.swing.JPanel;
javax.swing.JFrame;
javax.swing.JLabel;
java.awt.Rectangle;
javax.swing.JButton;
public class SinError extends JFrame {
private
private
private
private
private
static final long serialVersionUID = 1L;
JPanel jContentPane = null;
JPanel jPanel = null;
JLabel jLabel = null;
JButton jButton = null;
/**
* This is the default constructor
*/
public SinError() {
super();
initialize();
}
/**
* This method initializes this
*
* @return void
*/
private void initialize() {
this.setSize(300, 157);
this.setContentPane(getJContentPane());
this.setTitle("Enhorabuena");
this.setVisible(true);
}
/**
* This method initializes jContentPane
*
* @return javax.swing.JPanel
*/
private JPanel getJContentPane() {
if (jContentPane == null) {
jContentPane = new JPanel();
jContentPane.setLayout(new BorderLayout());
jContentPane.add(getJPanel(), BorderLayout.CENTER);
}
return jContentPane;
}
/**
* This method initializes jPanel
*
* @return javax.swing.JPanel
*/
private JPanel getJPanel() {
67
if (jPanel == null) {
jLabel = new JLabel();
jLabel.setBounds(new Rectangle(23, 24, 182, 32));
jLabel.setText("El archivo no contenía errores!! ");
jPanel = new JPanel();
jPanel.setLayout(null);
jPanel.add(jLabel, null);
jPanel.add(getJButton(), null);
}
return jPanel;
}
/**
* This method initializes jButton
*
* @return javax.swing.JButton
*/
private JButton getJButton() {
if (jButton == null) {
jButton = new JButton();
jButton.setBounds(new Rectangle(161, 69, 79, 29));
jButton.setText("Aceptar");
jButton.addActionListener(new
java.awt.event.ActionListener() {
public void
actionPerformed(java.awt.event.ActionEvent e) {
System.exit(0);
}
});
}
return jButton;
}
}
//
@jve:decl-index=0:visual-constraint="10,10"
En este caso de nuevo el botón Aceptar cierra la aplicación.
68
El paquete Principal
La clase Principal
Esta clase simplemente crea e inicializa un elemento de la clase
InterfazGráfica.
package principal;
import java.awt.Rectangle;
import interfazGrafica.InterfazGrafica;
public class Principal {
/**
* @param args
*/
public static void main(String[] args) {
InterfazGrafica ventana = new InterfazGrafica();
ventana.setBounds(new Rectangle(50, 50,400, 250));
}
}
69
Instrucciones de uso
Abrimos el programa y nos saldrá el menú principal que nos da la opción de Buscar un fichero
y otra de Analizarlo.
Al pulsar buscar nos sale el típico buscador de ficheros en nuestro ordenador, seleccionamos
el que queramos, en caso de que no sea HTML o HTM al pulsar analizar nos saltará otra
ventana informando del error y volveremos a poder buscar otro archivo.
70
Al pulsar analizar tenemos 4 opciones:
Que no se pueda establecer conexión con el w3c, entonces saltará la ventana:
Si no se encuentran errores corregibles nos muestra:
Que el archivo no contenga errores:
71
Que corrija los errores, entonces nos saldrá una ventana informando cuantos
errores podríamos corregir si se vuelve a pasar por el validador y da la opción
de hacerlo o salir
Si no quedan errores y pulsamos continuar se saldrá del programa.
72
Pruebas
Pruebas simples
Empezaremos esta sección con un archivo de prueba bastante simple para
cada tipo de error, a ver si es capaz de solucionarlo.
Error de tipo 28
28.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="es">
<head>
<title>Ejemplo</title>
</head>
<body>
<p>ejemplo</p> <!-- Comentario
</body>
</html>
La aplicación nos indica que ha terminado con éxito y el archivo queda como:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="es">
<head>
<title>Ejemplo</title>
</head>
<body>
<p>ejemplo</p> <!-- Comentario-->
</body>
</html>
Ahora probamos con 28_2.html que es idéntico pero el comentario parece
cerrado
<!—Comentario>
Vemos que todo sale correctamente <!—Comentario>-->
Error 42
42.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="es">
<head>
<title>Ejemplo</title>
</head>
<body>
<p >ejemplo</p> <!comentario-->
</body>
</html>
Tras pasar por la aplicación el comentario queda correcto
73
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="es">
<head>
<title>Ejemplo</title>
</head>
<body>
<p >ejemplo</p> <!--comentario -->
</body>
</html>
Errores 65-66
Introducimos 6566.html que tiene dos errores de este tipo
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="es">
<head>
<title>Ejemplo</title>
</head>
<body>
<ol>
<li> Práctica 05 </li>
<li><ul><li><a href="informes/Practica05horario.html">Horario</a></li>
<ul><li><a href="informes/Practica05horario.html">Horario</a></li>
</ul>
</ul></li>
</ol>
<dl>
<a href="informes/Practica06horario.html">Horario</a>
</dl>
</body>
</html>
Y como vemos nos los cierra con sus correspondientes etiquetas
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="es">
<head>
<title>Ejemplo</title>
</head>
<body>
<ol>
<li> Práctica 05 </li>
<li><ul><li><a href="informes/Practica05horario.html">Horario</a></li>
<li><ul><li><a href="informes/Practica05horario.html">Horario</a></li>
</ul>
</ul></li>
</ol>
<dl>
<dt><a href="informes/Practica06horario.html">Horario</a>
</dl>
74
</body>
</html>
Error 68
68.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="es">
<head>
<title>Ejemplo</title>
</head>
<body>
<ol>
<li> <p >ejemplo</p> </li>
</body>
</html>
En este caso es una etiqueta <ol> la que hay que cerrar y vemos que la cierra
tras los <li
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="es">
<head>
<title>Ejemplo</title>
</head>
<body>
<ol>
<li> <p >ejemplo</p> </li>
</ol> </body>
</html>
Con el archivo 68 segunda versión.html pasa lo mismo con los <dl>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="es">
<head>
<title>Ejemplo</title>
</head>
<body>
<dl>
<dt> ejemplo
<dd>
</dl></body>
</html>
Ahora le pasamos el archivo 68_3.html que tiene dos errores
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="es">
<head>
75
<title>Ejemplo</title>
</head>
<body>
<ol>
<li> ejemplo </li>
<li><a href="ej/ejemplo.html">Horario</li>
</body>
</html>
Observamos que nos ha cerrado bien ambas etiquetas
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="es">
<head>
<title>Ejemplo</title>
</head>
<body>
<ol>
<li> ejemplo </li>
<li><a href="ej/ejemplo.html">Horario</a></li>
</ol>
</body>
</html>
Error 79
79.html tiene dos etiquetas de cierre sin otra de inicio
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="es">
<head>
<title>Ejemplo</title>
</head>
</a>
<body>
<dl>
<dt> ejemplo
</dl> </dd>
</body>
</html>
La aplicación elimina las dos correctamente
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="es">
<head>
<title>Ejemplo</title>
</head>
76
<body>
<dl>
<dt> ejemplo
</dl>
</body>
</html>
Errores combinados
Vamos a probar un archivo que tenga dos errores distintos, el 68 y el 42
68y42.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="es">
<head>
<title>Ejemplo</title>
</head>
<body>
<ol>
<li> <p >ejemplo</p> </li>
</body>
<!comentario>
</html>
Y vemos que también nos queda corregidos
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="es">
<head>
<title>Ejemplo</title>
</head>
<body>
<ol>
<li> <p >ejemplo</p> </li>
</ol> </body>
<!--comentario>-->
</html>
Errores sucesivos
En 42yluego28.html primero nos detecta el error de que el comentario empieza
mal, y luego al volverlo a analizar detecta que está mal cerrado.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="es">
<head>
<title>Ejemplo</title>
</head>
<body>
<p>ejemplo</p> <!Comentario>
</body>
</html>
Tras Analizarlo una vez nos indica
77
Y al darle a continuar:
Al final tenemos el archivo totalmente corregido y además observamos que la
copia es del archivo original, o sea que ha funcionado y sólo lo ha copiado la
primera vez que lo ha corregido.
Ahora vamos a probar cuando no todo vaya como lo esperado.
Por ejemplo si introducimos de nuevo en la aplicación alguno de los anteriores
archivos ya corregidos.
Como están corregidos no devuelve ningún error y efectivamente nos sale la
ventana que indica que la aplicación no se encontró errores corregibles.
78
Al pulsar aceptar se cierra la aplicación
Si intentamos introducir un archivo sin la extensión .html
En este caso al pulsar aceptar se cierra la ventana de Información
79
Pruebas de páginas externas
Probaremos con páginas de belenus. Las validaremos en el w3c antes y
después de pasarlas por la aplicación
1. https://belenus.unirioja.es/~brflores/
El W3C nos devuelve el error:
end tag for element "A" which is not open
que es uno de los que nuestra aplicación debería arreglar.
Tras pasar por la aplicación no nos sale ningún error.
2. https://belenus.unirioja.es/~caruizg/
El W3C nos devuelve los errores:
end tag for element "A" which is not open
y 10 errores document type does not allow element "OL" here; assuming missing "LI" starttag
Tras pasar por la aplicación no nos sale ningún error
3. https://belenus.unirioja.es/~crbermej/
El W3C nos devuelve los errores:
9 errores document type does not allow element "OL" here; assuming missing "LI" start-tag
4. https://belenus.unirioja.es/~daguzman/
El W3C nos devuelve los errores:
10 errores document type does not allow element "OL" here; assuming missing "LI" start-tag
Tras pasar por la aplicación no nos sale ningún error
5. https://belenus.unirioja.es/~josuarez/
El W3C nos devuelve los errores:
2 errores document type does not allow element "UL" here; assuming missing "LI" start-tag
end tag for "ADDRESS" omitted, but its declaration does not permit this
end tag for "DIV" omitted, but its declaration does not permit this
Tras pasar por la aplicación no nos sale ningún error
En este caso nos fijamos que el error del ADDRESS lo ha corregido de una
forma que ya no da error, pero que queda sin sentido.
<address></address><a href="mailto:[email protected]">[email protected]</a>
6. https://belenus.unirioja.es/~vilancha/
El W3C nos devuelve los errores:
2 errores document type does not allow element "OL" here; assuming missing "LI" start-tag
Y 5 end tag for "A" omitted, but its declaration does not permit this
80
Tras pasar por la aplicación no nos sale ningún error.
¿Qué pasará si introducimos una página web grande que no esté en HTML
4.01 Strict?
En el validador nos da 180 errores si le pasamos la página www.formulatv.com
Al tener más errores de los permitidos por el tamaño del vector errores(100) se
queda el programa pillado.
¿Y si ejecutamos el validador sin conexión a internet?
Nos da error de W3C
Ya hemos visto que no tenemos problemas con la cantidad de errores, ni con la
falta de conexión.
También hemos visto que aunque algunos errores quedan solucionados ( el
validador no da error) , no queda con mucho sentido.
Por último vamos a probar casos que si el usuario no es muy desordenado no
deberían pasar.
Por ejemplo 68_4.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="es">
<head>
<title>Ejemplo</title>
</head>
<body>
<ol>
<li> <p >ejemplo</p>
</li>
<li> <p >ejemplo</p> </li>
</body>
</html>
Como está implementado para que si la etiqueta abierta sin cierre es un <ol>
en las siguiente líneas aparecerá un <li>, en este caso no ocurre así que nos
pone mal la etiqueta
<ol>
</ol>
<li> <p >ejemplo</p>
</li>
Lo cual nos genera más errores
Ahora vamos a pasarle el fichero 68y42 ,pero todo en la misma línea
68y42_2.html
En este caso se queda atascado y luego nos devuelve el control, si lo
ejecutamos desde la consola vemos que nos da un error relacionado con los
string.
81
82
Conclusiones
Al final hemos conseguido lo que pretendíamos, el inicio de una herramienta
que corrige algunos errores en los documentos y que está diseñada para
añadir soluciones fácilmente.
El gran problema del proyecto ha sido no poder enviar el archivo al w3c
directamente.
La solución encontrada de subir el archivo a un servidor, a parte de ralentizar la
ejecución de la aplicación, como no disponía de un servidor propio y usé uno
gratuito que pone al final del archivo publicidad, hace que en ciertos casos el
w3c nos lo tome como error, error que nuestro archivo original no tenía, aunque
la mayoría de las veces nuestra aplicación pasa por alto(ya que estas líneas de
código sólo se añaden en la versión que se sube al ftp, nuestro fichero no las
contiene en ninguna de sus versiones).
Otro error de lo que esta solución es culpable es del problema con ciertos
caracteres como las tildes o la ñ.
Seguramente si en vez de java hubiese elegido otro lenguaje como javascript
podría haber solucionado todo de otra manera, pero es el que mejor controlaba
y por eso lo elegí.
83
Bibliografía
No me he apoyado en ningún libro para hacer el proyecto, aunque si en varias
páginas web:
La api de JAVA para saber que clases usar y sus métodos
http://docs.oracle.com/javase/1.4.2/docs/api/
La documentación de los errores que lanza del w3c
http://validator.w3.org/docs/errors.html
Y en ciertos artículos de internet que me han sido de utilidad a la hora de
implementar:
http://www.ahristov.com/tutoriales/Trucos%2Bcortos%2Bde%2BJava/Detectarcodificacion-caracteres.html (método para saber la codificación de un fichero)
http://www.crazyteam.es/java/subir-y-bajar-ficheros-por-ftp/ ( método para subir
un archivo vía ftp)
http://inforux.wordpress.com/2008/08/06/aprendiendo-con-jfilechooser-parte-1/
(información de cómo buscar un fichero en el ordenador)
A parte también me he apoyado en conocimientos adquiridos en la carrera
como:
En los apuntes de la asignatura Diseño Tecnológico de Sistemas de
Información para todo el aspecto visual.
En los apuntes de la asignatura Proyectos para lo relacionado con la gestión
del proyecto.
84
Anexo: Reuniones
8 de Noviembre de 2010
Reunión Inicial cuando me asignaron el proyecto.
Hablamos de en lo que consistía la aplicación que tenía que hacer.
25 de Noviembre de 2011
Le había entregado el DOP y lo revisamos y quedé encargado de completarlo
con más información.
3 de Febrero de 2012
Miramos el documento de Análisis y me queda encargado acabarlo con las
revisiones y seguir con la fase de Diseño.
1 de Junio de 2012
Revisamos lo que llevo de memoria hasta ahora y un primer ejecutable de la
aplicación.
12 de Junio de 2012
Reunión final para ver el fin del proyecto y decidimos no presentarlo.
4 de Febrero de 2013
Reunión para ver qué cambios había que hacer al Análisis.
4 de Marzo 2013
Reunión para ver qué cambios había que hacer al Diseño.
8 de Abril de 2013
Reunión para ver qué cambios había que hacer a la implementación y resolver
el problema de conexión con el w3C.
8 de Julio de 2013
Reunión final para ver el fin del proyecto y entregarlo.
85