Crear tipos de contenidos «nested» en OpenCMS

Cuando creamos un contenido en OpenCMS podemos crear tipos de contenido que incluyan otros contenidos dentro, de forma que podamos «nestear» y asi poder tener tipos de contenidos que podemos usar en más de un tipo (o escalar) de forma sencilla.

Imaginemos (como ejemplo) que queremos crear un tipo de contenido llamado «pagina generica» el cual sera un contenido que tenga un titulo, subtitulo, párrafos de texto, imagenes, enlaces y adjuntos (ficheros). Pero que cada párrafo puede contener a su vez más imagenes, adjuntos… e incluso que los enlaces tengan descripciones (ademas del enlace en si, tanto externo como interno). Si hicieramos un unico contenido seria «grande» y podria ser poco usable, cuando lo importante es tener un contenido que «contenga» el resto.

Así, podemos crear un contenido llamado PaginaTexto que contenga contenidos Parrafo, Imagenes y Enlaces.


El contenido contenedor llamado PaginaTexto, podría ser así:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Ficha Tipo TEXTO -->
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
	
	<xsd:include schemaLocation="opencms://opencms-xmlcontent.xsd"/>
	<!-- Contenidos nesteados -->	
	<xsd:include schemaLocation="opencms://system/modules/com.contenidos.uva.es/schemas/nested/enlaces.xsd"/>
	<xsd:include schemaLocation="opencms://system/modules/com.contenidos.uva.es/schemas/nested/parrafos.xsd"/>
	<xsd:include schemaLocation="opencms://system/modules/com.contenidos.uva.es/schemas/nested/imagenes.xsd"/>
	<xsd:element name="PaginasTextos" type="OpenCmsPaginasTextos"/>
	
	<xsd:complexType name="OpenCmsPaginasTextos">
		<xsd:sequence>
			<xsd:element name="PaginaTexto" type="OpenCmsPaginaTexto" minOccurs="0" maxOccurs="unbounded"/>
		</xsd:sequence>
	</xsd:complexType>

	<xsd:complexType name="OpenCmsPaginaTexto">
		<xsd:sequence>
	
			<xsd:element name="Titulo" type="OpenCmsString" minOccurs="1" maxOccurs="1" />
			<xsd:element name="Subtitulo" type="OpenCmsString" minOccurs="1" maxOccurs="1" />
			<xsd:element name="Parrafo" type="OpenCmsParrafo" minOccurs="1" maxOccurs="unbounded" />
			<xsd:element name="Imagenes" type="OpenCmsImagen" minOccurs="0" maxOccurs="unbounded" />
			<xsd:element name="Adjuntos" type="OpenCmsVfsFile" minOccurs="0" maxOccurs="unbounded" />
			<xsd:element name="Meta" type="OpenCmsString" minOccurs="1" maxOccurs="1" />
			<xsd:element name="FechaModificacion" type="OpenCmsDateTime" />
		</xsd:sequence>
		<xsd:attribute name="language" type="OpenCmsLocale" use="required"/>
	</xsd:complexType>

	<xsd:annotation>
		<xsd:appinfo>
			<resourcebundles>
				<!-- textos de ayuda -->
				<xmlbundle name="com.contenidos.uva.es">
					<bundle locale="es">
						<resource key="label.OpenCmsPaginaTexto.Titulo">Titulo de la página</resource>
						<resource key="label.OpenCmsPaginaTexto.Texto">Texto generico de la página</resource>
					</bundle>
				</xmlbundle>
			</resourcebundles>
			<mappings>
				<!-- Mapeos -->
	
			</mappings>
			<validationrules>
				<!-- Reglas de validacion -->
				<rule element="Titulo" regex="!.*[Ee]rror.*" message="El titulo es obligatorio" />
			</validationrules>
			<layouts>
				<!-- Widgets a usar en los tipos -->
				<layout element="Adjuntos" widget="DownloadGalleryWidget" />
			</layouts>
			<defaults>
				<!-- Texto estandar -->
				<default element="FechaModificacion" value="${currenttime}" />
			</defaults>
		</xsd:appinfo>
	</xsd:annotation>  
</xsd:schema>

Donde, si vemos, nuestro contenido esta creado en un modulo llamado com.contenidos.uva.es, aunque eso no sea lo importante.

Si nos fijamos, lo importante son los includes donde tenemos 3 tipos que incluimos: enlaces.xsd, parrafos.xsd y enlaces.xsd que como vemos estan dentro de un directorio llamado nested dentro de los schemas.

Ademas, si nos fijamos en la definición del contenido OpenCmsPaginaTexto cuando definimos un elemento (por ejemplo Parrafo) el tipo de elemento es justamente el tipo de los otros esquemas incluidos.

Así, nested/imagenes.xsd sera:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Ficha Tipo Imagen -->
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
	
	<xsd:include schemaLocation="opencms://opencms-xmlcontent.xsd"/>

	<xsd:element name="Imagenes" type="OpenCmsImagenes"/>
	
	<xsd:complexType name="OpenCmsImagenes">
		<xsd:sequence>
			<xsd:element name="Imagen" type="OpenCmsImagen" minOccurs="0" maxOccurs="unbounded"/>
		</xsd:sequence>
	</xsd:complexType>

	<xsd:complexType name="OpenCmsImagen">
		<xsd:sequence>
			<xsd:element name="DescripcionImagen" type="OpenCmsString" maxOccurs="1" />
			<xsd:element name="Fichero" type="OpenCmsVfsFile" minOccurs="1" maxOccurs="1" />
			<xsd:element name="URL" type="OpenCmsString" minOccurs="0" maxOccurs="unbounded" />
		</xsd:sequence>
		<xsd:attribute name="language" type="OpenCmsLocale" use="optional"/>
	</xsd:complexType>

	<xsd:annotation>
		<xsd:appinfo>
			<resourcebundles>
				<!-- textos de ayuda -->
				<xmlbundle name="com.contenidos.uva.es">
					<bundle locale="es">
						<resource key="label.Imagen.Enlace">Enlace externo referencia de la imagen</resource>
						<resource key="label.Imagen.Descripcion">Descripcion de la imagen (texto corto)</resource>
						<resource key="label.Imagen.Imagen">Imágen asociada</resource>
					</bundle>
				</xmlbundle>
			</resourcebundles>
			<mappings>
				<!-- Mapeos -->
			</mappings>
			<validationrules>
				<!-- Reglas de validacion -->
				<rule element="DescripcionImagen" regex="!.*[Ww]arn.*" type="warning" message="Es conveniente que añada texto. Puede dejarlo vacio, pero no es recomendable" />
			</validationrules>
			<layouts>
				<!-- Widgets a usar en los tipos -->
				<layout element="Fichero" widget="ImageGalleryWidget" />
			</layouts>
			<defaults>
				<!-- Texto estandar -->
			</defaults>
		</xsd:appinfo>
	</xsd:annotation>  
</xsd:schema>

Tambien, nested/parrafos.xsd sera:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Ficha Tipo TEXTO -->
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
	
	<xsd:include schemaLocation="opencms://opencms-xmlcontent.xsd"/>
	<xsd:include schemaLocation="opencms://system/modules/com.contenidos.uva.es/schemas/nested/enlaces.xsd"/>
	<xsd:include schemaLocation="opencms://system/modules/com.contenidos.uva.es/schemas/nested/imagenes.xsd"/>

	<xsd:element name="Parrafos" type="OpenCmsParrafos"/>
	
	<xsd:complexType name="OpenCmsParrafos">
		<xsd:sequence>
			<xsd:element name="Parrafo" type="OpenCmsParrafo" minOccurs="0" maxOccurs="unbounded"/>
		</xsd:sequence>
	</xsd:complexType>

	<xsd:complexType name="OpenCmsParrafo">
		<xsd:sequence>
			<xsd:element name="Texto" type="OpenCmsHtml" minOccurs="1" maxOccurs="1" />
			<xsd:element name="Enlace" type="OpenCmsEnlace" minOccurs="0" maxOccurs="unbounded" />
			<xsd:element name="Imagen" type="OpenCmsImagen" minOccurs="0" maxOccurs="unbounded" />
			<xsd:element name="Documento" type="OpenCmsVfsFile" minOccurs="0" maxOccurs="unbounded" />
		</xsd:sequence>
		<xsd:attribute name="language" type="OpenCmsLocale" use="optional"/>
	</xsd:complexType>

	<xsd:annotation>
		<xsd:appinfo>
			<resourcebundles>
				<!-- textos de ayuda -->
				<xmlbundle name="com.contenidos.uva.es">
					<bundle locale="es">
						<resource key="label.OpenCmsParrafo.Texto">Texto de la subseccion</resource>
						<resource key="label.OpenCmsParrafo.Enlace">Enlaces de la subsección</resource>
						<resource key="label.OpenCmsParrafo.Documento">Documento añadido</resource>
					</bundle>
				</xmlbundle>
			</resourcebundles>
			<mappings>
				<!-- Mapeos -->
			</mappings>
			<validationrules>
				<!-- Reglas de validacion -->
				<rule element="Texto" regex="!.*[Ww]arn.*" type="warning" message="Es conveniente que añada texto. Puede dejarlo vacio, pero no es recomendable" />
			</validationrules>
			<layouts>
				<!-- Widgets a usar en los tipos -->
				<layout element="Documento" widget="DownloadGalleryWidget" />
			</layouts>
			<defaults>
				<!-- Texto estandar -->
			</defaults>
		</xsd:appinfo>
	</xsd:annotation>  
</xsd:schema>

Y nested/enlaces.xsd será:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Ficha Tipo ENLACE -->
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
	
	<xsd:include schemaLocation="opencms://opencms-xmlcontent.xsd"/>

	<xsd:element name="Enlaces" type="OpenCmsEnlaces"/>
	
	<xsd:complexType name="OpenCmsEnlaces">
		<xsd:sequence>
			<xsd:element name="Enlace" type="OpenCmsEnlace" minOccurs="0" maxOccurs="unbounded"/>
		</xsd:sequence>
	</xsd:complexType>

	<xsd:complexType name="OpenCmsEnlace">
		<xsd:sequence>
			<xsd:element name="Descripcion" type="OpenCmsString" maxOccurs="1" />
			<xsd:element name="URL" type="OpenCmsString" minOccurs="1" maxOccurs="unbounded" />
		</xsd:sequence>
		<xsd:attribute name="language" type="OpenCmsLocale" use="optional"/>
	</xsd:complexType>

	<xsd:annotation>
		<xsd:appinfo>
			<resourcebundles>
				<!-- textos de ayuda -->
				<xmlbundle name="com.contenidos.uva.es">
					<bundle locale="es">
						<resource key="label.Enlace.Titulo">Descripción del enlace</resource>
						<resource key="label.Enlace.URL">Enlace</resource>
					</bundle>
				</xmlbundle>
			</resourcebundles>
			<mappings>
				<!-- Mapeos -->
			</mappings>
			<validationrules>
				<!-- Reglas de validacion -->
			</validationrules>
			<layouts>
				<!-- Widgets a usar en los tipos -->
				<layout element="URL" widget="LinkGalleryWidget" />
			</layouts>
			<defaults>
				<!-- Texto estandar -->
			</defaults>
		</xsd:appinfo>
	</xsd:annotation>  
</xsd:schema>

Donde, lo más curioso es que los subesquemas incluyen otros esquemas a su vez en su propia definición de datos. Con lo que podemos hacerlo tan complejo como queramos.

Destacar que los esquemas «nesteados» han de llevar obligatoriamente en la definición del lenguaje:

<xsd:attribute name="language" type="OpenCmsLocale" use="optional"/>

Es decir, en modo opcional y no requerido ya que solo un elemento ha de llevarlo en requerido.

El resultado será el siguiente:

tuti

Técnico en Comunicación Interna de la UVa

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.