Referencia de etiquetas XSP
Dentro de xsp:page se pueden usar etiquetas para generar un contenido algo más
dinámico. Algunas de ellas son propias de XSP (las que pertenecen al espacio de nombres xsp)
y otras son definidas por el usuario. A continuación se detallan las etiquetas nativas:
- <xsp:structure>: Engloba directivas globales a nivel de programa. Debe colgar
directamente de xsp:page.
- <xsp:include>: Permiten importar módulos de forma según el lenguaje. En el caso de
Java el contenido del xsp:include es transformado en imports. Por ejemplo
<xsp:include>java.util.Date</xsp:include> se transformaría en:
import java.util.Date ;
- <xsp:logic>: Especifica que su contenido debe ser considerado como código embebido
en la página.
- <xsp:content>: Usado dentro de un bloque <xsp:logic>
indica que el contenido pasa a ser considerado como XML para el documento final.
- <xsp:expr>: Se usa para evaluar variables o expresiones y colocar su resultado en el
documento generado.
- Si el contenido de xsp:expr es de un tipo primitivo, se inserta en un nodo de
texto su representación como cadena.
- Si el resultado de evaluar la expresion es instancia de alguna subclase de
org.w3c.dom.Node se insertan si pertenecen al mismo documento o se clonan
e insertan si pertenecen a un documento distinto (para cambiar el Document
propietario).
- Si la expresión es de tipo String se insertará dentro de un nodo de texto.
Nótese que si la cadena representa un fragmento de XML éste no será
insertado como tal, sino como texto normal de forma que los caracteres ">",
"<" y "&" serán escapados.
- Si la expresión es un Array, se tratará como un
org.w3c.dom.DocumentFragment y se le añadirá cada elemento del array
como hijo aplicándole estas mismas reglas.
- Si el resultado no es de ninguno de estos tipos se insertará como nodo de
texto basado en un toString() del objeto.
- <xsp:element>: Permite insertar un nuevo elemento en el documento cuyo nombre
será el especificado en el atributo name de esta etiqueta. El contenido de la etiqueta será
el contenido del elemento. Es útil si el nombre del elemento se decide dinámicamente. Por ejemplo:
<clock>
<xsp:element name=time><xsp:content><xsp:expr>new
Date()</xsp:expr><xsp:content></xsp:element>
</clock>
se traducirá en el documento final en:
<clock>
<time>Wed Jul 04 15:12:49 CEST 2001</time>
</clock>
- <xsp:attribute>: Permite añadir un atributo al nodo actual. El nombre del atributo será
el especificado en el atributo name de la etiqueta y el valor será su contenido. Por
ejemplo:
<clock>
<xsp:attribute name=time><xsp:expr>new Date()</xsp:expr></xsp:attribute>
</clock>
se traducirá en el documento final en:
<clock time="Wed Jul 04 15:12:49 CEST 2001"/>
- <xsp:pi>: Permite insertar una instrucción de proceso en el documento generado. El
nombre de la instrucción de proceso vendrá determinado por el atributo target de esta
etiqueta. El contenido será colocado dentro del cuerpo de la instrucción de proceso. Por
ejemplo:
<xsp:pi target="process">
href="<xsp:expr>request.getQueryString()</xsp:expr>"
type="forward"
</xsp:pi>
Se traducirá en:
<?process href="http://www.aqs.com/xsp/example" type="forward"?>
- <xsp:comment>: Permite insertar un texto a modo de comentario dinámico en el
documento generado. El texto del comentario será el contenido de esta etiqueta. Por
ejemplo:
<xsp:comment> Bla Bla Bla </xsp:comment>
Se traducirá en:
Bla Bla Bla
Aunque pueda parecer más razonable algo como <!-- Bla Bla Bla -->,
este es el comportamiento actual de Cocoon (v1.82).
Ahora sólo queda por ver cómo pueden colocarse estas etiquetas. Puesto que en una XSP no
se sabe a priori que elementos van a aparecer, difícilmente se puede hacer una DTD o un
schema rigurosos, por lo que se va a dar una notación alternativa que debe entenderse como
orientativa más que como determinante.
| Etiqueta |
Contenido válido |
Atributos |
| xsp:page |
xsp:structure (?) , xsp:logic (?) , [user root] |
language
indent-result: yes | no
xmlns:xsp
xml:space: default | preserve
[user name_space definitions] |
| xsp:structure |
xsp:dtd (?), xsp:include (*) |
|
| xsp:dtd |
[texto] |
|
| xsp:include |
[texto] |
|
| [user root] |
(
[texto] | xsp:attribute(*) | xsp:logic (*) |
xsp:element (*) | xsp:expr (*) | xsp:pi (*) | xsp:comment |
[user tag] (*)
)* |
[user root attributes] |
| xsp:attribute |
(
[texto] | xsp:expr (*)
)* |
name
xml:space: default | preserve |
| xsp:logic |
(
[texto (código embebido)] | xsp:content (*) |
xsp:pi (*) | xsp:comment
)* |
xml:space: default | preserve |
| xsp:content |
(
[texto (XML)] | xsp:logic (*) |
xsp:expr(*) | xsp:element (*) | xsp:pi (*) |
xsp:comment (*)| [user tag] (*)
)* |
|
| xsp:pi |
(
[texto] | xsp:expr
)* |
target |
| xsp:comment |
(
[texto] | xsp:expr(*)
)* |
|
| xsp:element |
(
[texto] | xsp:attribute (*) | xsp:element (*)|
xsp:logic (*) | xsp:expr (*) | [user tag] (*)
)* |
name |
| xsp:expr |
[texto] |
|
| [user tag] |
(
[texto] | xsp:attribute(*) | xsp:logic (*) |
xsp:element (*) | xsp:expr (*) | xsp:pi (*) |
xsp:comment | [user tag] (*)
)* |
[user root attributes] |
| Leyenda |
(?) -> 0 ó 1 | (+) -> 1 ó más | (*) -> 0 ó más | Si no, 1 |
El uso típico de estas etiquetas es:
- Una etiqueta <xsp:page> después de las instrucciones de proceso. Este será el
elemento raíz de la XSP (no del documento generado).
- Una etiqueta <xsp:structure> que contiene la lista de importaciones mediante
etiquetas <xsp:include>.
- A continuación puede venir una etiqueta <xsp:logic> donde se escribirá la lógica a
nivel de clase (es decir, definiciones de atributos y de métodos).
- Después ha de venir una etiqueta definida por el usuario. Esta será la raíz del
documento generado y su contenido pasará a formar parte del método
populateDocument() de XSPPage.
Dentro de la etiqueta xsp:page sólo puede haber una etiqueta no xsp.
- Dentro de la raíz de usuario se puede escribir en dos modos para generar el
documento final: En modo XML y en modo código embebido.
- En el modo XML se pueden escribir directamente etiquetas XML que
pasarán a formar parte del documento generado. Este es el modo por
defecto dentro del elemento raíz definido por el usuario. Para pasar a modo
XML se introduce una etiqueta <xsp:content>. Si en este modo se
quiere insertar el resultado de evaluar una expresión o una variable
definidos en un bloque de lógica se debe usar una etiqueta <xsp:expr>.
En este modo también se pueden insertar elementos y atributos usando
<xsp:element> y %lt;xsp:attribute>.
- En el modo de código embebido se puede escribir código fuente usando la
sintaxis del lenguaje elegido en el atributo language del elemento
xsp:page, normalmente Java. Este código pasará a formar parte
directamente del código fuente generado para la XSPPage. Para pasar a
este modo hay que usar una etiqueta <xsp:logic>. No hay que olvidar
que una XSP es un documento XML y como tal tiene ciertos caracteres
reservados que hay que escapar. Estos son:
- "<" -> "<"
- ">" -> ">"
- "&" -> "&"
Así, por ejemplo, para escribir:
if ( (a > 10) && (a < 20) ) {
. . .
}
se tendría que escribir en la XSP:
if ( (a > 10) && (a < 20) ) {
. . .
}
o, de forma alternativa:
<![CDATA[
if ( (a > 10) && (a < 20) ) {
. . .
}
]]>
Las XSP proveen de ciertas facilidades al desarrollador:
Ya se incluyen por defecto muchos imports frecuentes:
- java.io.*;
- java.util.*;
- org.w3c.dom.*;
- org.xml.sax.*;
- javax.servlet.*;
- javax.servlet.http.*;
- org.apache.cocoon.parser.*;
- org.apache.cocoon.producer.*;
- org.apache.cocoon.framework.*;
- org.apache.cocoon.processor.xsp.*;
También se instancian objetos corrientes para que estén ya en la página listos para ser
usados. Estos son:
- request. El objeto HttpServletRequest que encapsula la petición.
Se trata de un wrapper del objeto real que recibe Cocoon, pero con la misma funcionalidad.
- response. Un wrapper del objeto
HttpServletResponse que
recibe Cocoon. Ofrece todas las funciones del objeto real salvo el
acceso al ServletOutputStream para preservar la consistencia de la
salida manejada por Cocoon.
- session. El objeto HttpSession.
- servletContext. El objeto ServletContext estándar.
- document. El org.w3c.Document
donde se van insertando todos los
elementos hasta conformar el resultado final.
- xspGlobal. Es un contenedor de información compartida a nivel de
aplicación. Su existencia viene justificada porque el objeto
servletContext de versiones del JSDK anteriores a la 2.2 no
admitían su uso para mantener información compartida a nivel de
aplicación. En futuras versiones, este objeto será depreciado.
- xspNodeStack. Una pila (java.util.Stack) para controlar la
anidación de los elementos del documento.
- xspCurrentNode. El org.w3c.Node actual.
- xspParentNode. El org.w3c.Node padre del nodo actual.
- xspParser. Un DOM parser proporcionado por Cocoon.
Una vez conocidos los elementos que puede contener una XSP y cómo pueden combinarse
y el entorno de objetos y clases accesibles, se pasará a explicar aspectos interesantes para
el desarrollador sobre cómo funciona internamente una XSP.
La primera vez que se invoca una XSP, comienza el proceso de transformaciones del XML
hasta llegar al código fuente de la XSPPage. Se produce una transformación por cada
espacio de nombres definido en el elemento xsp:page que se corresponda con una
logicsheet (nombre que da Cocoon a las taglibs) definida en el
cocoon.properties. Esto se verá con mayor detalle en el apartado
dedicado a las taglibs. La última transformación convierte el XML a código fuente en el
lenguaje indicado (por el momento Java). Este código fuente incluye:
- Un nombre de paquete generado por Cocoon.
- Una lista de imports mezcla de los predefinidos y de los definidos por el usuario con
xsp:include.
- Un nombre de clase generado por Cocoon. Esta clase extiende XSPPage.
- Si colgando de xsp:page cuelga un bloque xsp:logic, esta lógica se introducirá tal cual
dentro de la clase. Por lo que se puede aprovechar para definir atributos y métodos.
- El contenido del elemento raíz definido por el usuario será transformado en código para
generar XML dentro del método populateDocument(). Este método declara que puede
lanzar Exception, por lo que no será necesario introducir este código dentro de un
try-catch, ya que estas excepciones las recoge Cocoon para generar una página de
error. Aunque no sea necesario es recomendable controlar en cada momento estos
errores y no permitir que aparezca la pantalla de error de Cocoon.
Tras la generación del código fuente se procede a la compilación de la página. Tanto el
código fuente como el compilado son guardados en sendos archivos según la estructura de
paquetes generada a partir del directorio repository (nombre por defecto, que se puede
cambiar en el cocoon.properties) en el raíz del servidor.
Posteriormente Cocoon invoca el método populateDocument()
de la XSPPage para obtener el XML resultante.
Este XML puede ser reprocesado por Cocoon si incluye más instrucciones de proceso. El
proceso más habitual es la transformación con ayuda de XSLT, aunque también se pueden
usar instrucciones de formateo y de acceso a bases de datos.
Para asignar una XSL al resultado de la XSP se debe incluir 2 instrucciones de proceso
especiales después de la instrucción de proceso de XSP:
<?cocoon-process type="xslt"?>
<?xml-stylesheet type="text/xsl" href="<ruta_archivo_xsl>"?>
También se puede asignar de forma dinámica desde el código de la página:
<xsp:page ......>
<root>
<xsp:logic>
Node rootNode = xspCurrentNode;
String MY_XSL = "myXSL.xsl";
...//more code and more XML
document.insertBefore(
document.createProcessingInstruction(
"cocoon-process",
"type=\"xslt\""
), nodeRoot
);
document.insertBefore(
document.createProcessingInstruction(
"xml-stylesheet",
"href=\""+MY_XSL+"\" type=\"text/xsl\""
), nodeRoot
);
...//more code and more XML
</xsp:logic>
</root>
</xsp:page>
En el próximo capítulo se describe un ejemplo de XSP.