Académique Documents
Professionnel Documents
Culture Documents
LENGUAJES DE MARCAS Y
SISTEMAS DE GESTIÓN DE INFORMACIÓN
UNIDAD DE TRABAJO 5:
XML. TRATAMIENTO Y
RECUPERACIÓN DE DATOS
http://informatica.iesbeniajan.es
http://creativecommons.org/licenses/by-nc-sa/3.0/es/
LMSGI U.T.5: TRATAMIENTO Y RECUPERACIÓN DE DATOS
UNIDAD DE TRABAJO 5:
TRATAMIENTO Y RECUPERACIÓN DE DATOS
Contenido
1.- INTRODUCCIÓN
En esta unidad se introducirán las bases de datos XML nativas, que son una alternativa a las relacionales. Se
sustituyen las tablas con sus campos por documentos XML con sus elementos y atributos.
Para practicar con este tipo de bases de datos, se utilizará el sistema gestor de bases de datos BaseX,
y aprenderemos dos lenguajes de consulta de documentos XML:
Por un lado se conocerá XPath, un lenguaje sencillo de expresiones que permite acceder a partes de un
documento XML.
Por otro lado se aprenderá XQuery, otro lenguaje, que hace uso de XPath, y que facilitará la
manipulación de documentos XML. Se podrá extraer partes de un documento, generar documentos
nuevos a partir de los datos de los originales, etc.
Todas las bases de datos relacionales están centradas en los Datos, pues lo que ellas almacenan en sus
campos son datos simples, más conocidos como datos atómicos. Una base de datos nativa en XML, no posee
campos, ni almacena datos atómicos, sino que almacena documentos XML. Por lo tanto, a este tipo de bases
de datos se les denomina bases de datos centradas en documentos. Mientras que las base de datos
relacionales son adecuadas para almacenar datos, las bases de datos nativas XML son adecuadas para
almacenar documentos.
A continuación vamos a iniciarnos en el manejo de BaseX, que será el sistema gestor de bases de datos
nativas XML que emplearemos en esta unidad.
2.2.- BASEX
BaseX es un motor de bases de datos nativo XML, ligero, de alto rendimiento en las operaciones y fácilmente
escalable. Incluye, así mismo, procesadores de XPath y XQuery. Con BaseX se puede crear una base de datos
que esté constituida por uno o más documentos XML. Ya no son tablas como en los sistemas gestores de
bases de datos relacionales, sino documentos XML.
Después podremos acceder al contenido de estos documentos con diferentes lenguajes de consulta,
como XPath y XQuery.
Con BaseX podemos visualizar de diferentes formas el documento XML que estamos manejando:
En formato texto (resultado)
En forma de árbol
En la imagen anterior se pueden observar las secciones más importantes de la interfaz gráfica de
BaseX:
Barra de menús en la parte superior.
Barra de herramientas (botones) inmediatamente debajo.
Línea de comandos justo debajo de la barra de herramientas.
Editor de consultas.
Diversas visualizaciones de los datos.
Además podemos visualizar información sobre las consultas ejecutadas.
Se va a utilizar este programa, sencillo en su manejo, como herramienta para introducir dos
lenguajes de consulta de documentos XML: XPath y XQuery.
Lo necesario para comenzar es saber cómo crear bases de datos XML nativas. Para ello, basta
Copyleft - José Manuel Rubira Miranda 2018 5
LMSGI U.T.5: TRATAMIENTO Y RECUPERACIÓN DE DATOS
con seleccionar el menú Base de Datos y la opción Nuevo. Aparecerá una ventana donde se solicita seleccionar
un archivo XML o un directorio que contenga algún archivo XML. BaseX puede crear bases de datos asociadas
a uno o a varios archivos XML. Una vez seleccionado el archivo o directorio y asignado un nombre a la base de
datos, se accederá a la interfaz cuyas imágenes se han estado mostrando.
La mayoría de los ejemplos del presente documento se basan en una base de datos llamada BD_Bailes
creada a partir del documento BD_Bailes.xml, y en una base de datos llamada formacionProfesional creada a
partir del documento formacionProfesional.xml, parte de cuyo contenido se muestra a continuación:
BD_Bailes.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<Bailes>
<baile id="1">
<nombre>Tango</nombre>
<precio cuota="mensual" moneda="euro">27</precio>
<plazas>20</plazas>
<comienzo>1-1-2011</comienzo>
<fin>1-12-2011</fin>
<profesor>Roberto García</profesor>
<sala>1</sala>
</baile>
<baile id="2">
<nombre>Cha-cha-cha</nombre>
<precio cuota="trimestral" moneda="euro">80</precio>
<plazas>18</plazas>
<comienzo>1-2-2011</comienzo>
<fin>31-7-2011</fin>
<profesor>Miriam Gutiérrez</profesor>
<sala>1</sala>
</baile>
...
</Bailes>
3.- XPATH
XPath forma, junto con XSLT y XSL-FO (ambos se verán en la próxima unidad), una familia de lenguajes
llamada XSL, diseñados para acceder, transformar y dar formato de salida a documentos XML. La versión más
reciente de XPath es la 2.0, que introduce algunas novedades respecto a la 1.0. Los ejemplos que aquí se
verán son compatibles con la 1.0 y se indicará cuando se introduzca alguno específico de la 2.0.
XPath es un lenguaje de expresiones que no se usa de manera independiente, sino que suele usarse
incrustado en otros lenguajes más potentes, como XQuery o XSLT.
Una expresión XPath es una cadena de texto que representa un recorrido en el árbol que representa un
documento XML. Las expresiones más simples se parecen a las rutas de los archivos en el explorador de
Windows o en la shell de GNU/Linux.
Evaluar una expresión XPath es buscar si hay nodos en el documento que se ajustan al recorrido
definido en la expresión. El resultado de la evaluación son todos los nodos que se ajustan a la expresión. Para
poder evaluar una expresión XPath, el documento debe estar bien formado.
Los tipos de nodos en XPath se corresponden con el tipo de contenido que podemos encontrar en un
documento XML: raíz del documento (/), nodo documento (o elemento raíz o elemento documento),
elementos, atributos, texto, comentarios, instrucciones de procesamiento y espacios de nombres.
Los tipos de datos básicos son: string, number, boolean y node-set (conjunto de nodos).
Las expresiones XPath, al igual que los direccionamientos en un sistema de ficheros, pueden ser
absolutas (empiezan por /) o relativas (con respecto a un nodo determinado, llamado nodo de contexto).
Con / al principio de una expresión, especificamos que se trata de la raíz del documento
Si separamos un elemento de otro o un elemento de un atributo utilizando el carácter /, indicamos que
el segundo elemento o el atributo están incluidos dentro del primer elemento.
Ejemplo.- Selecciona el atributo id de todos los bailes
//baile/@id/data()
Si separamos un elemento de otro o un elemento de un atributo utilizando los caracteres //, indicamos
que el segundo elemento o el atributo son descendientes del primer elemento.
Ejemplo.- Selecciona el atributo cuota descendiente de todos los bailes
//baile//@cuota/data()
Con [ ] podemos especificar una condición a aplicar a un elemento, o la posición de un determinado
elemento.
Ejemplo.- El primer baile del documento
/Bailes/baile[1]
Cuando se escribe una ruta en XPath, por ejemplo a un cierto elemento /Bailes/baile/nombre, lo que se
devuelve es el conjunto de nodos llamados nombre, descendientes de baile, descendientes de Bailes,
descendiente del nodo raíz. Si no existiera esa ubicación, se devolvería el conjunto vacío.
Hay analizadores de expresiones que devuelven directamente el contenido textual del nodo o
nodos accedidos. Pero ante la duda, y para indicar al analizador que lo que se desea es el contenido textual,
se utilizará la función text() a continuación de la expresión de acceso al nodo, de la forma:
/Bailes/baile/nombre/text()
Para acceder a un atributo se emplea el símbolo @. Por ejemplo, para acceder a un atributo id de
baile, se escribirá /Bailes/baile/@id. Para mostrar de forma explícita el valor de los atributos se usará
la función data(), de la forma:
/Bailes/baile/@id/data()
En XPath 2.0 se usa la misma función string() para ambos casos, según se muestra a continuación:
/Bailes/baile/nombre/string()
/Bailes/baile/@id/string()
Son rutas equivalentes a las que indicaríamos en un direccionamiento absoluto en un sistema Linux, es decir,
desde la raíz hasta el elemento del cuál queremos extraer la información. La particularidad respecto a los
sistemas de ficheros es que un nodo puede tener varios hijos que se llamen igual, mientras que en un sistema
de ficheros no puede haber dos directorios hijos de un mismo directorio padre que se llamen igual. Veamos
algunos ejemplos con el documento formacionProfesional.xml.
Ejemplo.- Todos los elementos hijos del nodo raíz, es decir, el elemento documento:
/*
Ejemplo.- Todos los atributos de cualquier elemento del documento XML:
//@*/data()
A partir de aquí hay que recurrir a los elementos de XPath, comunes a cualquier lenguaje de programación,
que serán necesarios para generar expresiones más complejas. En particular, los operadores y las funciones.
3.4.1.- Operadores
Podemos utilizar múltiples operadores para construir las consultas XPath y XQuery. Veamos los más comunes.
Operadores Matemáticos: +, -, * , div, mod
Ejemplo.- Para cada baile, suma del número de plazas más el número de la sala (no tiene mucho sentido,
pero es sólo por probar el operador):
/Bailes/baile/(plazas+sala)
Operadores de Comparación y booleanos: =, !=, <, >, <=, >=, and, or, not()
Ejemplo.- Nombre de los bailes en los que hay más de 15 plazas (empleamos la función number() para tratar
el parámetro como un número)
/Bailes/baile[number(plazas)>15]/nombre/text()
No obstante, la mayoría de los procesadores de XPath y XQuery son capaces de optimizar las consultas
y procesar los valores como números aunque no se indique explícitamente. Por ejemplo, la anterior consulta
sin emplear number, en BaseX:
/Bailes/baile[plazas>15]/nombre/text()
Se optimizaría antes de ser procesada como:
Consulta Optimizada:
db:open-pre("BD_Bailes",0)/*:Bailes/*:baile[15.0 < *:plazas]/*:nombre/text()
3.4.2.- Funciones
Las funciones más utilizadas en XPath son las que se indican a continuación.
avg( ): Calcula el valor medio de los valores referenciados por la variable o expresión que se le pasa.
Ejemplo.- Calcula la media de plazas de todos los bailes.
/Bailes/avg(baile/plazas)
Otras funciones numéricas de interés son: min( ), max( ), sum( ), round(), floor(), ceiling(), number().
Ejemplo.- Calcula la media de plazas de todos los bailes, redondeada.
/Bailes/round(avg(baile/plazas))
Funciones de cadena
contains( ): Esta función permite buscar un texto dentro de una cadena de texto
Ejemplo.- Nombre de los bailes que contienen una ‘n’ en su nombre
/Bailes/baile[contains(nombre,"n")]/nombre/text()
Otras funciones de cadena de interés son: concat( ), substring(), starts-with(), translate(), string-
length(), normalize-space().
Ejemplo.- Cuatro primeros caracteres de los nombres de los ciclos
Copyleft - José Manuel Rubira Miranda 2018 11
LMSGI U.T.5: TRATAMIENTO Y RECUPERACIÓN DE DATOS
/fP/ciclos/ciclo/substring(nombre,1,4)
Ejemplo.- Todos los nodos del árbol cuyo nombre tenga una longitud de cuatro caracteres
//*[string-length(name())=4]
Se trata de una extensión de las expresiones anteriores mediante la cual se puede seleccionar elementos en
función del valor de sus atributos o del propio elemento. En este caso los valores serán literales. Como ya se
ha visto en algunos ejemplos previos, se indican las condiciones entre corchetes junto al elemento al cual se
aplican. Los valores literales se indican entre comillas.
Ejemplo.- Nombre de los ciclos cuyas siglas se encuentren, en orden alfabético, entre ASIR y SMR
/fP/ciclos/ciclo[@siglas>"ASIR" and @siglas<"SMR"]/nombre/text()
Ejemplo.- Datos del segundo módulo de la lista de los cursados en primer curso:
/fP/modulos/modulo[curso="1"][2]
Ejemplo.- Nombre de los módulos cuya relación (cociente) entre duración y ects sea mayor de 10:
/fP/modulos/modulo[(duracion div ects) >= 10]
Es el mismo caso que el anterior pero con valores recuperados mediante otras expresiones.
Ejemplo.- Nombre de los ciclos en los que se cursen módulos de una duración de 80 horas o más. Primero:
En los elementos módulo se seleccionan aquellos que tengan una duración de 80 horas o más y se obtienen
las siglas de los ciclos en los que se cursan:
/fP/modulos/modulo[duracion>=80]/ciclos/ciclo/@siglas
Copyleft - José Manuel Rubira Miranda 2018 13
LMSGI U.T.5: TRATAMIENTO Y RECUPERACIÓN DE DATOS
Segundo: Se muestran los nombres de los elementos ciclo cuyas siglas sean iguales a las extraídas en el paso
primero:
/fP/ciclos/ciclo[@siglas=/fP/modulos/modulo[duracion>=80]/ciclos/ciclo/@siglas]/nombre/te
xt()
Ejemplo.- Nombres de módulos que tengan una duración mayor que la del módulo "Sistemas operativos
monopuesto". Se usa la función number() para obtener el valor numérico de la duración, de lo contrario
haría la comparación como cadenas (donde se cumple que "100"< "20"):
/fP/modulos/modulo[number(duracion)>=/fP/modulos/modulo[nombre="Sistemas operativos
monopuesto"]/number(duracion)]/nombre
En XPath, los ejes son expresiones que permiten acceder a trozos del árbol XML, apoyándose en las relaciones
de parentesco o jerarquía entre los nodos. Con los ejes obtenemos un conjunto de nodos relacionados de
alguna forma con el nodo actual o nodo de contexto.
Ejemplo.- Devuelve los nodos que aparecen en el documento después del segundo elemento ciclo:
/fP/ciclos/ciclo[2]/following::*
Ejemplo.- Devuelve los elementos hermanos menores del segundo elemento ciclo:
/fP/ciclos/ciclo[2]/following-sibling::*
La novedad más llamativa es que dispone de los mismos tipos de datos predefinidos que los esquemas XML:
xs:string, xs:boolean, xs:date, ... Aparecen así mismo algunas funciones nuevas, como lower-case() o upper-
case() para pasar cadenas de texto a minúsculas y mayúsculas respectivamente.
4.- XQUERY
XQuery es un lenguaje de consulta que permite extraer y procesar información almacenada en formato XML,
habitualmente en bases de datos nativas XML o en tablas y campos de tipo XML en bases de datos
relacionales.
También se asemeja a XPath, con el que comparte modelo de datos y soporta las mismas funciones y
operadores. Se podría considerar a XQuery como un superconjunto de XPath, ya que toda expresión XPath es
una expresión XQuery válida.
XQuery es muy amplio, pero aquí sólo se ofrecerá una visión introductoria. Al igual que se ha hecho
con XPath, para su estudio se utilizará el motor de bases de datos nativo BaseX. En este caso, con la base de
datos de ejemplo basada en el documento factbook.xml, que se incluye en la instalación de BaseX (ubicado en
la ruta etc/factbook.xml), se creará una base de datos de nombre mondial, de manera que se puede hacer
referencia al documento XML indistintamente como etc/factbook.xml o como mondial. Además seguiremos
utilizando la base de datos BD_Bailes empleada con XPath. Para probar las expresiones XQuery utilizaremos el
editor que incorpora BaseX.
En XQuery todo es una expresión que se evalúa a un valor. Por ejemplo, 7+3 es un código válido en XQuery
que se evalúa a 10. Otro ejemplo es una expresión condicional que devuelve un texto:
if (3 < 4) then "Verdadero" else "Falso"
Al evaluarse devolverá el texto Verdadero.
Los tipos de datos primitivos (predefinidos) o atómicos (no compuestos) son los mismos que los de los
esquemas XML.
Numéricos: enteros y reales.
Booleanos.
Cadenas de texto.
Copyleft - José Manuel Rubira Miranda 2018 15
LMSGI U.T.5: TRATAMIENTO Y RECUPERACIÓN DE DATOS
Fechas, horas y duraciones.
Tipos relacionados con XML, como QName.
Nodos XML: nodo raíz, elemento, atributo, texto, comentario, instrucción de procesamiento y espacio
de nombres.
Con la función doc( ) se lee el documento XML que se indica como parámetro y devuelve el nodo raíz o los
elementos que se indiquen mediante una expresión XPath. En la función doc() se puede especificar un nombre
de documento XML o el nombre de una base de datos. Si no incluimos la función doc(), se entiende que la
consulta se dirige a la base de datos actualmente abierta.
Ejemplo.- Con la ruta XPath //city/name se obtienen una serie de nombres de ciudades (ubicadas en
cualquier lugar del árbol XML), que se guardan en la variable $city. De ellas nos quedamos con las que
empiecen por Q, se ordenan y se muestran.
for $city in doc('mondial')//city/name
where starts-with($city,'Q')
order by $city
return data($city)
En la cláusula return, la función data() devuelve el contenido o valor del elemento, variable o atributo
que se le pasa. Si se pasa más de un parámetro, se debe poner todo entre paréntesis.
FLWOR son las siglas de For, Let, Where, Order by y Return (en inglés se lee flower), y son una serie de
cláusulas que se usan para construir expresiones XQuery. A continuación se muestra la sintaxis básica de las
cláusulas FLWOR:
for $nombreVariable in doc(Documento o BBDD XML)/Ruta_Elementos
let $nombreOtrasVariables := valorAsignado
where condición
order by criteriosOrdenación [ascending|descending]
return valoresRetornados
Para devolver u obtener más de un valor o resultado empleando la cláusula return, debemos incluir las
diferentes expresiones entre paréntesis y separadas por comas.
Ejemplo.- A partir del documento XML de ejemplo factbook.xml, mostramos los países del continente
europeo.
for $continente in doc("mondial")/mondial/continent
for $pais in doc("mondial")/mondial/country
where $continente/@id=$pais/encompassed/@continent and $continente/@name="Europe"
return data($pais/@name)
Analicemos este ejemplo:
Se declara una variable $continente que contiene todos los elementos /mondial/continent.
Se declara una variable $pais que contiene todos los elementos /mondial/country.
Se vinculan datos de los elementos en $continente, de los que disponemos de su identificador
almacenado en el atributo id, con los elementos en $pais, de los que disponemos del identificador del
continente donde se ubican, almacenado en el atributo continent del elemento encompassed.
Se hace sólo para los continentes cuyo nombre es Europa.
Se devuelve el nombre de los países ubicados en Europa.
El resultado es: Albania Andorra Austria Belarus Belgium Bosnia and Herzegovina ...
Si queremos ordenar el resultado aplicando más de un criterio, separaremos las diferentes expresiones con
una coma.
Ejemplo.- Muestra el profesor y el nombre de cada baile ordenados por el nombre del profesor y por el del
baile.
for $bai in doc("BD_Bailes")/Bailes/baile
order by $bai/profesor, $bai/nombre
return ($bai/profesor, $bai/nombre)
Por defecto, la ordenación de los elementos retornados es ascendente; si queremos hacerla descendente, es
suficiente con añadir el término descending tras la expresión de ordenación.
Ejemplo.- Muestra el nombre y el profesor de cada baile ordenados descendentemente por el nombre del
baile.
for $bai in doc("BD_Bailes")/Bailes/baile
order by $bai/nombre descending
return ($bai/nombre,$bai/profesor)
4.4.3.- Comentarios
Para incluir un comentario en una consulta XQuery, debemos acotar el comentario entre las expresiones (: y
:).
Ejemplo.-
for $bai in doc("BD_Bailes")/Bailes/baile
order by $bai/nombre descending
(: Ahora especifico los resultados :)
return ($bai/nombre,$bai/profesor)
Contamos prácticamente con las mismas funciones que vimos para XPath. Veamos algunos ejemplos:
contains( ): Esta función permite buscar un texto dentro de una cadena de texto
Ejemplo.- Muestra los profesores que se llamen Roberto
for $baile in doc("BD_Bailes")//Bailes/baile
where contains($baile/profesor,"Roberto")
return $baile/profesor
count( ): Cuenta el número de elementos o nodos referenciados por la variable que se le pasa como
parámetro.
Ejemplo.- ¿Cuántos bailes se realizan en la sala número 1?
for $bailes in doc("BD_Bailes")//Bailes
return count($bailes/baile[sala = 1])
O también:
count(for $baile in doc("BD_Bailes")//Bailes/baile
where ($baile/sala=1)
return $baile)
Copyleft - José Manuel Rubira Miranda 2018 18
LMSGI U.T.5: TRATAMIENTO Y RECUPERACIÓN DE DATOS
avg( ): Calcula el valor medio de los valores referenciados por la variable o expresión que se le pasa.
Ejemplo.- Calcula la media de plazas de todos los bailes.
for $bailes in doc("BD_Bailes")//Bailes
return avg($bailes/baile/plazas)
Otra forma:
let $media := avg(doc("BD_Bailes")//baile/plazas)
return $media
Ejemplo.- Se devuelve la media de los valores obtenidos en uno de los ejemplos anteriores.
avg (for $organizaciones in doc('mondial')/mondial/organization
return count($organizaciones/members))
Se pueden incluso combinar funciones, como en el caso siguiente en el que se redondea a dos
decimales el resultado de la media anterior con la función round-half-to-even():
round-half-to-even(
avg
(for $organizaciones in doc('mondial')/mondial/organization
return count($organizaciones/members)),2)
Otras funciones de interés son: min( ), max( ), sum( ), concat( ), replace(), substring(), ...
En algunos casos, sobre todo cuando se trata de consultas sencillas, será posible utilizar tanto expresiones
XPath como expresiones FLWOR para obtener un resultado correcto.
Ejemplo.- Muestra los nombres de los bailes que tengan más de 15 plazas.
Expresións XPath:
doc("BD_Bailes")/Bailes/baile[plazas > 15]/nombre
Consulta FLWOR:
for $bai in doc("BD_Bailes")/Bailes/baile
where $bai/plazas > 15
return $bai/nombre
Hasta ahora sólo hemos realizado consultas sobre los datos almacenados en la bases de datos XML. Veamos
ahora de forma breve cómo podemos llevar a cabo operaciones de actualización de esos datos, es decir,
inserciones, modificaciones y eliminaciones.
4.7.1.- Inserción
Con esta orden hemos insertado un nuevo nodo (un elemento <baile>) en la base de datos BD_Bailes.
La ubicación del nuevo nodo está determinada por la cláusula before, con la que especificamos que queremos
insertar el nuevo elemento antes del elemento que especificamos a continuación, en este caso, antes del
primer elemento <baile>, es decir, que el nuevo nodo pasa a ser el primer elemento <baile>.
Ejemplo.- Queremos añadir los datos de un nuevo baile como último nodo hijo dentro del elemento <Bailes>.
insert node
<baile id="8">
<nombre>Del caballo</nombre>
<precio cuota="mensual" moneda="dolares">40</precio>
<plazas>18</plazas>
<comienzo>02/05/2013</comienzo>
<fin>30/06/2013</fin>
<profesor>José Manuel</profesor>
<sala>5</sala>
</baile>
as last into doc("BD_Bailes")/Bailes
4.7.2.- Modificación
Si queremos modificar el contenido de una base de datos XML, podemos optar por modificar un nodo
completo (replace node) o modificar el valor de un nodo (replace value of node)
Ejemplo.- Queremos cambiar el profesor del baile que aparece en primer lugar por el de "Antonio Niotona".
replace value of node
doc("BD_Bailes")/Bailes/baile[1]/profesor
with "Antonio Niotona"
Ejemplo.- Queremos modificar el número de plazas del baile que aparece en primer lugar, pero en vez de
modificar sólo el valor, vamos a modificar el nodo completo.
replace node
doc("BD_Bailes")/Bailes/baile[1]/plazas
with <plazas>14</plazas>
Las operaciones de modificación sólo pueden afectar a un único nodo. Si queremos modificar más de
un nodo debemos hacer uso de una expresión FLWOR.
También podemos emplear expresiones FLWOR para llevar a cabo las modificaciones
for $bai in doc('BD_Bailes')/Bailes/baile
where contains($bai/profesor/text(),'u')
return replace value of node $bai/profesor
with "Nombre con letra u"
Para borrar un nodo de una base de datos XML empleamos la instrucción delete.
Otros, como ORACLE, permiten almacenar XML "de alguna manera" dentro de las tablas relacionales. A
continuación mostraremos las capacidades del SGBD ORACLE para tratar con documentos XML. Si bien los
sistemas gestores de bases de datos de Oracle son aplicaciones con licencia propietaria, se pueden descargar
gratuitamente del sitio de Oracle siempre que el fin de su uso no sea lucrativo. Podemos utilizar por ejemplo la
versión 11 g Release 2, que encontraremos en el sitio de Oracle
(http://www.oracle.com/technetwork/products/express-edition/downloads/index.htrnl), donde tendremos que
crear una cuenta gratuita para poder descargarla. Haciendo una instalación sin personalizar, a base de aceptar
las opciones por defecto, podremos tener disponible el sistema gestor. Sólo se nos pedirá una única
contraseña para los usuarios administradores por defecto, SYS y SYSTEM. Una vez instalado, utilizaremos SQL
Developer (o el "espartano" SQL*Plus, un cliente de línea de comandos), para ejecutar las sentencias de
ejemplo. La conexión se realizará con el usuario SYSTEM. Aunque el emplear un usuario con privilegios de
administración va contra la ortodoxia en el manejo de sistemas gestores de bases de datos, para un caso
simplificado como éste nos valdrá. No obstante, podemos crearnos un usuario específico ejecutando las
siguientes instrucciones:
CREATE USER LMSGI IDENTIFIED BY lmsgi;
GRANT CONNECT, RESOURCE TO LMSGI;
CONN LMSGI/lmsgi;
En Oracle podremos disponer de tablas con campos de tipo XML, o bien de tablas en las que
cada fila es, directamente, un documento XML. En ambos casos, se les puede asociar un esquema XML que
valide el documento XML.
La instrucción de creación de una tabla Contratos con un campo de tipo XML (XMLTYPE) llamado contenido,
será:
CREATE TABLE Contratos
(
idContrato NUMBER,
fecha DATE,
contenido XMLTYPE
);
Copyleft - José Manuel Rubira Miranda 2018 22
LMSGI U.T.5: TRATAMIENTO Y RECUPERACIÓN DE DATOS
Para insertar un registro que contenga datos relacionales, así como un valor para el campo XML
contenido, ejecutaremos:
INSERT INTO Contratos VALUES (100, TO_DATE('01/01/1990'),
XMLType('<?xml version="1.0"?>
<contrato id="100">
<fecha>2015-01-01</fecha>
<lugar>Dublín</lugar>
</contrato>')) ;
Una consulta para mostrar el contenido del campo XML podría ser:
SELECT C.contenido contratoXML
FROM Contratos C;
(Atención: el cliente SQL*PLUS tiene un bug al visualizar los contenidos XML. Sí funciona correctamente con
SQL*Developer, en cambio.)
La siguiente consulta devolvería el lugar del contrato extraído directamente del campo XML. Para ello,
se utiliza la función extract() sobre el citado campo. Adicionalmente, se usa la función getStringVal() para
tratar la información extraída como una cadena de texto. Si fuera de tipo numérico se usaría en su lugar
getNumVal():
SELECT C.contenido.extract('/contrato/lugar/text()').getStringVal()
FROM Contratos C;
Otra función equivalente a extract() es extractValue(), que permite extraer un dato de un campo XML
sin tener que preocuparse de qué tipo es. La sintaxis cambia con respecto a extract(), ya que recibe dos
parámetros, el campo de tipo XML y la expresión XPath que indicará qué información se extrae:
SELECT extractValue(C.contenido,'/contrato/fecha') Fecha
FROM Contratos C;
Se podría realizar otra consulta con la función existsNode(), que verifica si existe un cierto elemento en
el campo XML. Devuelve 1 si existe y 0 si no.
Ejemplo.- Mostrar el valor del campo contenido (de tipo XML) de la tabla Contratos, para aquel contrato con
identificador igual a 100 y que contenga un elemento lugar, descendiente de /contrato.
SELECT C.contenido contratoXML
FROM Contratos C
WHERE C.contenido.existsNode('/contrato[@id = "100"]/lugar')=1;
También se pueden ejecutar consultas XQuery sobre campos de tipo XML. Para ello se utiliza la función
XMLQuery(), que recibirá como parámetros la consulta XQuery, además del nombre del campo XML.
Ejemplo.- Mostrar el identificador del contrato (campo relacional) y el lugar del contrato (extraído del campo
XML).
SELECT idcontrato, XMLQuery (
'for $c in /contrato
order by $c/lugar
Copyleft - José Manuel Rubira Miranda 2018 23
LMSGI U.T.5: TRATAMIENTO Y RECUPERACIÓN DE DATOS
return $c/lugar'
passing by value C.contenido
RETURNING CONTENT) DatosXMLRecuperados
FROM Contratos C;
Es interesante también la función XMLTable(), que mapea el resultado de una expresión XQuery,
realizada en el FROM de la consulta SELECT, con una tabla relacional virtual (semejante a una vista) cuyos
campos, de tipos de datos propios del sistema gestor con el que se trabaja, pueden ser referenciados.
XMLTable() --> Convierte el resultado de una consulta XQuery en una tabla "virtual".
Ejemplo.- A partir de una expresión XQuery sobre un campo XML, se construye una tabla virtual C2 con dos
campos, Lugar (del tipo VARCHAR2) y Fecha (del tipo DATE), que pueden ser referenciados.
SELECT C1.idContrato, C2."Lugar", C2."Fecha"
FROM Contratos C1,
XMLTABLE('/contrato'
PASSING C1.contenido
COLUMNS
"Lugar" varchar2(10) PATH '/contrato/lugar',
"Fecha" DATE PATH '/contrato/fecha') C2 ;
Para las modificaciones y eliminaciones se emplearán las instrucciones SQL update y delete.
UPDATE Contratos SET contenido =
XMLType('<?xml version="1.0"?>
<contrato id="100">
<fecha>2015-09-21</fecha>
<lugar>Beniaján</lugar>
</contrato>')
WHERE idContrato = 100;
Una forma adicional de consultar la tabla XML es haciendo alusión a la meta-columna object_value, que
muestra el contenido del documento XML almacenado en cada registro:
SELECT object_value FROM ContratosXML;
Copyleft - José Manuel Rubira Miranda 2018 24
LMSGI U.T.5: TRATAMIENTO Y RECUPERACIÓN DE DATOS
Para modificar el contenido de un documento almacenado en una tabla XML, se usará la función
updateXML(), dentro de un proceso de modificación (UPDATE) de registros.
Ejemplo.- Se quiere modificar el valor del nodo /contrato/lugar de aquel contrato cuyo identificador valga
100, pasando a valer Múnich.
UPDATE ContratosXML C
SET OBJECT_VALUE = updateXML(OBJECT_VALUE,'/contrato/lugar/text()','Múnich')
WHERE existsNode(OBJECT_VALUE,'/contrato[@id="100"]')=1;
Con la función deleteXML() se pueden eliminar elementos de un documento XML. En sí mismo, se trata
de un proceso de modificación (UPDATE) de un registro de la tabla XML.
Ejemplo.- Se quiere eliminar el elemento /contrato/fecha de aquel contrato cuyo lugar de celebración sea
Múnich.
UPDATE ContratosXML C
SET OBJECT_VALUE =
deleteXML(OBJECT_VALUE, '/contrato/fecha')
WHERE existsNode(OBJECT_VALUE, '/contrato[lugar="Múnich"] ')=1;
6.- BIBLIOGRAFÍA
Documentación oficial de BaseX
http://docs.basex.org/wiki/Main_Page