ndice de contenido
1.- Sistemas de almacenamiento de la informacin.........................................................................1 2.- Utilizacin de XML para almacenamiento de la informacin....................................................5 3.- Lenguajes de consulta manipulacin..........................................................................................6 4.- XQUERY....................................................................................................................................8 5.- Consultas (Flwor a HTML)......................................................................................................18 6.- Actualizacin (insercin, borrado, modificacin)....................................................................31 7.- Exportacin de libreras XML..................................................................................................36 8.- Otras funciones o libreras........................................................................................................37 9. Ejemplo Cooperativa Agraria....................................................................................................38
BD Jerrquica: Utilizan rboles para almacenar la informacin (nodo raz, nodos padre/hijos, nodos hoja), de manera que la extraccin de los datos se realiza mediante un recorrido del rbol y eligiendo la rama por la que debe continuar su bsqueda. Este tipo de estructuras son muy eficientes en las bsquedas pero no pueden reflejar eficientemente la redundancia de datos. BD de Red: Muy parecida a las jerrquicas pero donde un nodo puede tener varios padres simultneamente (en contraposicin de las bases de datos jerrquicas). BD Relacional: Es una base de datos que permite resolver el problema que tenan las bases de datos jerrquicas (las redundancias). Mientras que las jerrquicas la posicin del dato en
Pag: 1/40
el rbol era importante, en las relacionales es irrelevante. Un conjunto de datos compacto y con sentido propio se almacena en algo llamado tupla. Una tupla no es ms que una fila de una tabla en la que se almacena dicha informacin compacta. El conjunto de tuplas con informacin semntica igual determina una tabla. Y un conjunto de tablas pueden ser relacionadas con otras tablas (o tuplas), mediante tablas intermedias que reflejan las relaciones entre cada una de ellas. Esto es lo que soluciona la redundancia de informacin y son las ms utilizadas actualmente. BD Transaccional: Utilizan el concepto de transaccin (que veremos ms adelante) que permite asegurar una serie de caractersticas importantes en los sistemas informticos de hoy en da. Estas caractersticas se incluyeron en la mayora de las bases de datos relacionales de hoy en da. BD Multidimensional: A efectos sera una base de datos Relacional en el que en vez de tener tablas (2D), tendramos estructuras con N dimensiones para almacenar la informacin (cubos si fuese 3D). BD Orientadas a Objetos: Difiere de las bases de datos relacionales en que no se almacena la informacin por tuplas sino por objetos que contienen la informacin y los mtodos que son necesarios para tratarlas. Es llevar la programacin orientada a objetos al mundo de las bases de datos generando caractersticas como la herencia, la encapsulacin o el polimorfismo.
Como puede observarse, dependiendo del modelo de datos que se quiera almacenar, se deber utilizar una base de datos u otra. Independientemente del modelo usado, cuando se tiene un gran conjunto de bases de datos, lo comn es utilizar un Sistema de Gestin de Bases de Datos o SGBD, que unifiquen las bases de datos entre s y se mejoren los flujos de distribucin de la informacin en diferentes entornos y/o formatos. Para obtener ms informacin, vea la pgina http://www.maestrosdelweb.com/principiantes/que-son-las-bases-de-datos/. Bsicamente se deja de utilizar los almacenes de informacin de las aplicaciones (los ficheros) para utilizar un interfaz de comunicacin nico (el SGBD y una BD concreta). Su utilizacin permite: Evitar la redundancia de datos que puede producirse por la duplicacin de los mismos ficheros de datos utilizados en distintas aplicaciones y/o ubicaciones. Permiten la abstraccin de los datos independientemente del sistema hardware/software utilizado y del soporte utilizado para su almacenamiento. Evitar la inconsistencia de los datos cuando diferentes programas intentan actualizar un dato que es compartido. Evitar que el cambio o adicin de nueva informacin no planeada en el anlisis inicial del sistema obligue a la adaptacin de todos los programas informticos que utilizan esos ficheros. Evitar que la mala programacin en el acceso/modificacin/borrado de los datos en un fichero genere problemas de seguridad. Tener una capa de aplicacin y una capa de datos distinta facilita la depuracin y la trazabilidad de los programas. La abstraccin, independencia, consistencia, seguridad y accesibilidad son los objetivos que se buscan en estos sistemas. Adems su funcionamiento suele ser muy simple. Se puede resumir en un comentario muy acertado de D. ngel Garca Moreno, catedrtico de la Universidad Politcnica de
Enrique Mora Moral. Pag: 2/40
Madrid y profesor de la asignatura de Bases de Datos en la Ingeniera Informtica: "Mientras que con los mtodos clsicos se acceda a la informacin a travs de ficheros y los datos paseaban por los programas; en los SGBD son los programas los que se dan una vuelta por las Bases de Datos para conseguir lo que necesitan". Estos beneficios hacen que la prctica totalidad de los sistemas que quieran almacenar informacin recurran a un sistema de bases de datos acorde a sus necesidades, garantizando: Gestionar la redundancia para evitarla o al menos limitarla. Mantener los datos separados de las aplicaciones que lo usan. Localizar los datos en una ubicacin desde la cual, las aplicaciones puedan acceder de manera distribuida, concurrente y asegurando la integridad de los mismos. Permite realizar una correcta poltica de copias de seguridad, ya que ya no es necesario ir copiando los ficheros en distintas ubicaciones. En un SGBD no todo son ventajas. Existen una serie de inconvenientes que es necesario resaltar para tomar en el futuro una decisin adecuada. Como inconvenientes se pueden enumerar los siguientes: Un SGBD no es fcilmente administrable. Requiere de personal especializado en administracin de sistemas y lenguajes de consultas contra las bases de datos. Una buena administracin de los sistemas y de las bases de datos puede salvar la continuidad del negocio. Si los datos son simples y no requiere de acceso concurrente de usuarios o aplicaciones, puede ser sustituido por un simple fichero, como por ejemplo un archivo binario o un fichero XML. No es sencillo formar al personal que trabaja con los datos almacenados en un SGBD si no tiene un perfil orientado hacia la informtica. El personal de nminas de una empresa, por ejemplo, no tiene porqu aprender un lenguaje de programacin de consultas. Requerir que el sistema le proporcione una interfaz de comunicacin tipo formulario de consultas que oculte la complejidad del sistema. Poner en funcionamiento un SGBD requiere de un coste inicial en hardware y software que puede no ser necesario para las necesidades normales de un entorno pequeo. Siempre habr que realizar un anlisis de los beneficios y los inconvenientes que aportan la integracin de estos SGBD en un entorno de trabajo concreto. Un requisito que hasta el momento no se ha nombrado y que por exigencias del mercado se ha aadido en los SGBD modernos es el soporte transaccional. Una transaccin es un conjunto de rdenes en secuencia que, en su conjunto, determina un trabajo completo. El trabajo es completo si y solo si se cumplen todas y cada una de sus operaciones en el orden dado. Tras la ejecucin de una transaccin solo existen dos resultados posibles: Finalizada con xito. No completada (y asegura que no se ha cambiado nada). Veamos un ejemplo de cmo de importante es una transaccin. Supongamos que un usuario quiere sacar dinero de un cajero automtico. La transaccin es "sacar dinero". Para ello se siguen una serie de pasos secuenciales que permiten realizar la transaccin con xito: 1.Validacin del usuario (insercin del PIN). 2.Seleccin del importe a sacar.
Enrique Mora Moral. Pag: 3/40
3.Anotacin en la cuenta bancaria del reintegro. 4.Expedir tique y el dinero solicitado al usuario. Si est en el paso nmero 3 y despus hubiera un corte en el suministro elctrico, el usuario tendra anotada en su cuenta bancaria un reintegro que nunca ha sido entregado al usuario (paso 4). Obviamente el usuario se enfadara y reclamara. Una transaccin, si es ejecutada de manera exitosa, asegura que los pasos del 1 al 4 se han seguido en ese orden y que todo ha salido bien. Si la transaccin no ha sido exitosa, asegura que ni el dinero ha salido por el cajero, ni que tampoco se ha anotado el reintegro en la cuenta bancario del usuario (incluso aunque haya habido un corte en el flujo elctrico y estuviese la transaccin en el paso 3). Es decir, al no ser exitosa la transaccin es como si nunca hubiese pasado. Esto que, explicado con un ejemplo es tan simple, su nombre tcnico en un SGBD se denomina caractersticas ACID, acrnimo de: Atomicidad (Atomicity): Es la propiedad que asegura que una transaccin no se ha quedado a medias. O se ha ejecutado completamente o ninguna de las acciones intermedias ha sido llevada a cabo en la base de datos. Consistencia (Consistency): Una vez se ha determinado que la transaccin ha sido exitosa, debe quedar reflejados sus resultados en la base de datos dejando totalmente consistente e integra la base de datos. Aislamiento (Isolation): Una transaccin no puede afectar a otra en el transcurso de su ejecucin. Esto implica que dos transacciones que trabajen sobre el mismo conjunto de informacin no puede generar informacin inconsistente o error alguno en el sistema. Durabilidad (Durability): Una vez realizada la transaccin, sus resultados permanecern inalterables, independientemente de si surgen problemas en el sistema. Esto no quiere decir que una transaccin posterior no pueda modificar los datos anteriormente modificados (s podra pero no de manera concurrente con otra transaccin). Hasta el momento no se ha hablado de cmo est definido un SGBD, por lo que se podra pensar que es un nico bloque funcional, hecho ad hoc, para resolver un problema de almacenamiento de datos concreto. En realidad un SGBD puede verse como un conjunto de actores y componentes que se intercomunican entre s para hacer ms fcil el acceso a los datos. Estos componentes son: El Hardware: Dispositivos fsicos donde residen todos los dems componentes del SGBD. Normalmente son dispositivos con capacidades de redundancia y con alta disponibilidad para soportar cualquier contingencia que surja durante su funcionamiento. El Software: Aplicacin que permite abstraerse de las caractersticas fsicas del hardware y que permite hacer al SGBD ser independiente de la plataforma hardware sobre la que se ejecuta. Los Datos: Informacin almacenada dentro del recinto fsico (hardware) y administrada por el software. Los Usuarios: Actores a los que se les permite interactuar con el SGBD, hacindoles transparente el acceso a los datos, independientemente del Hardware o Software utilizado. En relacin a los usuarios, depender del software SGBD que se vaya a utilizar pero genricamente podemos identificar los siguientes roles: Administrador del Sistema informtico. Administrador de la Base de datos y Consultas. Usuario Final.
Pag: 4/40
Los anteriores componentes se unen entre s haciendo que el sistema sea modular y fcil de usar/administrar.
nicamente queda por hablar del sistema hardware que se debe utilizar para llevar a cabo la instalacin de un SGBD. Para pequeas y medianas empresas cualquier servidor relativamente moderno puede servir. Todo depender del grado de concurrencia de accesos y la cantidad de datos a almacenar los que determinarn las caractersticas fsicas del hardware. Pero lo que debe ser fundamental es el dimensionamiento del almacn de datos para que no se quede pequeo. Desde la mquina analtica de Charles Babbage hasta los netbook de hoy en da, el almacenamiento de la informacin ha pasado por muchas etapas: El cableado fsico. La tarjeta perforada. La cinta mgnetica. El disco duro. Los disquetes. El CD-ROM / DVD. Las tarjetas de memoria. Los pendrives. Los discos duros en estado slido. Es claro que los discos duros actuales estn alcanzando tamaos impensables, lo que el almacenamiento de datos puede no ser un problema. Simplemente sustituyendo un disco por otro de mayores dimensiones el problema se resuelve y adems es seguro que ser ms rpido que el antiguo (lo que aceleran las transferencias de informacin).
XML. Ello permite representar muchas clases de datos, incluso aquellos procedentes de fuentes no XML. Al hablar de introducir el tema de la consulta en un documento XML es obligado analizar las posibilidades que existen de emular en este terreno, las posibilidades que conocemos existen con el uso de SQL en el modelo relacional, que es la gran referencia en Informtica para la consulta de datos. Vamos a resear las diferencias existentes entre datos XML y datos relacionales: a) Metadatos: los datos relacionales presentan estructuras regulares y homogneas (cada fila tiene las mismas columnas con los mismos nombres y tipos) lo que permite usar metadatos sin ningn problema, mientras en XML los datos son heterogneos e irregulares (pgina web, captulo de libro, etc.) con estructuras diferentes que deben describirse caso a caso, de forma que estos metadatos se acaban describiendo en el propio documento. b) Anidamiento: los documentos XML contienen distintos niveles de anidamiento, que son irregulares e impredecibles, mientras que los datos relacionales son planos al estar organizados a partir de tablas. c) Jerarqua: en XML existe una jerarqua y un orden intrnseco que no se da en la estructura relacional, ello se refleja en la forma de trabajar de XPath (el quinto objeto rojo, los objetos que estn despus de A y antes de X, etc.) cuando este orden y esta jerarqua carece de relevancia en el modelo relacional. d) Densidad: los datos relacionales son densos (cada columna un valor) y los inexistentes se declaran como tales (con null), en cambio los datos en XML son dispersos, y la informacin que no existe sencillamente carece de elemento. Como consecuencia XML es ms libre que el modelo relacional a la hora de enfrentarse con datos faltantes. e) Mecanismo de consulta: en XML el resultado de una consulta consiste inevitablemente en una secuencia heterognea de elementos, atributos y valores primitivos, que a su vez pueden servir de intermediarios para procesar una expresin de mayor nivel, cosa que difiere de SQL, donde toda expresin dentro de una consulta devuelve una tabla. Ello significa que un lenguaje de consulta para XML debe proporcionar necesariamente funciones constructoras que sean capaces de crear en el proceso estructuras anidadas que pueden ser complejas; se trata de requisitos que en cambio son irrelevante en el caso relacional con el uso de SQL. Ante las consideraciones anteriores, que conducen a la conclusin de que no siempre las cosas que pueden ser objeto de consulta en un documento lo puedan ser en una Base de Datos relacional y viceversa, W3C decidi que las consultas en XML deban ser objeto de un nuevo lenguaje, que se llam XQuery.
incorpore el correspondiente proceso de validacin. Compatibilidad con XPath: al basarse en este lenguaje de localizacin de la familia XML, se pueden identificar las partes de un documento y con ello recuperar la informacin deseada. Posibilidad de Composicin: la totalidad de las distintas expresiones basadas en XPath sean condicionales o cualquieras otras, deben poder combinarse entre ellas con la mxima generalidad. Ello significa en la prctica, que el resultado de cualquier expresin se debe poder usar como operando de otra. Completitud: aunque sin conseguir una potencia expresiva comparable a la completitud del modelo relaciona], XQuery debe ser capaz de obtener un documento XML construido a partir de documentos diferentes, siempre usando para ello el clculo de predicados de primer orden y las funciones recursivas. Generalidad: el lenguaje debe poder aplicarse tanto en entornos que usen tipos de datos muy estrictos y bien especificados, como en otros, donde los tipos de entrada y salida se descubran en tiempo de ejecucin, e incluso con datos que carezcan de cualquier tipado. En otras palabras, XQuery debe poder trabajar con documentos descritos de formas muy distintas, sea un Esquema, una DTD o incluso carecer de cualquier descripcin. Semntica: no deben existir grandes restricciones semnticas a la hora de proporcionar el resultado de una consulta. Esta exigencia es debida al hecho de que la obtencin de un valor en estas consultas puede consistir en ninguno, uno o muchos tems, que a su vez pueden ser elementos, atributos o valores primitivos, lo que hace que sea necesario que todo operador XQuery tenga bien definidas todas las posibilidades que puedan aparecer. El cumplimiento de lo anterior conduce inevitablemente a una semntica compleja, y al objeto de simplificarla en XQuery se definen operadores con operaciones implcitas. As por ejemplo, los operadores aritmticos que se utilicen (como +) cuando se aplican a un elemento, automticamente extraen su valor numrico, mientras que por su parte los operadores de comparacin (como =) aplicados a una secuencia de valores, de forma automtica, iteran buscando los valores que satisfagan la comparacin. Como puede verse se trata de trabajar con los mayores grados de libertad posible en la semntica a la hora de efectuar una consulta. Anlisis esttico: asumiendo que el proceso de consulta tiene dos fases: anlisis y evaluacin (parecido a la compilacin y ejecucin de un programa.) en XQuery se optimiza el anlisis y el proceso de deteccin de errores, decidindose automticamente qu errores se permiten y cules no. De estos requisitos se constata que el objetivo de XQuery se centra mucho ms en la recuperacin de informacin que en la actualizacin de documentos ya existentes, por lo que en la prctica las consultas XQuery tienden a ajustarse a las tareas que puedan interaccionar con aquellas cosas que ya estn almacenadas siguiendo la sintaxis de XML.
Pag: 7/40
4.- XQUERY
El modelo de datos de XQuery se basa en representar los datos XML en forma de nodos y valores, que sirven de operandos y resultados de los operadores XQuery. En este modelo se representa uno o ms documentos XML con una secuencia definida como una coleccin de uno o ms tems, donde un tem es un nodo o un valor atmico. Dos caractersticas importantes son: 1) Los nodos en XQuery se corresponden con los siete nodos del modelo XPath (documento, elemento, atributo, etc.) 2) Los valores atmicos usados a corresponden con los tipos simples predefinidos de los Esquemas (cadenas, booleanos, decimales, etc.). En el modelo XQuery cada nodo elemento o atributo consta de: nombre (una cadena) anotacin de tipo valor tipado, tal como lo determina el proceso de validacin en Esquemas y en el caso de que estuviera sin validar o sin tipo adopta la anotacin xs:anyType. Como se observa, el modelo XQuery se apalanca en la estructura XML que ya conocemos, de forma que toda consulta se basa en el rango de datos que usa el documento analizado, esto es, un rbol etiquetado y ordenado, cuyos nodos tienen una identidad que puede estar asociada a tipos de datos simples o complejos. Ello permite que XQuery pueda usarse tanto para consultar documentos con datos sin tipar, como gobernados por Esquemas, o aquello que obedece a una DTD. XQuery es un lenguaje funcional cuya sintaxis es la de XML aunque parecida a la de XPath, con lo que toda consulta es una expresin que debe evaluarse. Adelantemos que una consulta acerca de todos los ttulos de los captulos de un documento como personas.xml, se puede hacer con la expresin tal como: doc("personas.xml ")/personas/persona/nombre Con este ejemplo intentamos extraer los nombres de las personas almacenadas en nuestro documento personas.xml. Como era lgico pensar, una expresin XQuery puede estar compuesta de otras de ms bajo nivel que se combinan mediante operadores y palabras clave, de forma que tras su anlisis, toda expresin acaba siendo una secuencia heterognea de nodos y valores atmicos. Podemos realizar consultas a colecciones. Las consultas a colecciones nos consultan varios ficheros XML almacenados en un directorio a la vez. Por ejemplo, para consultar los <nif> de las personas de todos los ficheros p*.xml: for $p in collection("./?select=p*.xml")/personas/persona/nif return $p Se pueden construir XML directamente con XQUERY con la siguiente sintaxis: element curso { attribute fechaNacimiento { 1996}, element p {"Nombre de la primera persona"}, element p { doc("personas.xml")/personas/persona[1]/nombre } }
Enrique Mora Moral. Pag: 8/40
Donde puede utilizar constantes y valores extrados con XQUERY para montar una estructura fija. El resultado de la anterior consulta devuelve: <?xml version="1.0" encoding="UTF-8"?> <curso fechaNacimiento="1996"> <p>Nombre de la primera persona</p> <p> <nombre> nombre5</nombre> </p> </curso> Donde este segundo nombre lo ha extrado del fichero anterior.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE personas SYSTEM "file:/media/Datos/Curso11-12/proyecto1/personas.dtd"> <personas> <persona edad="25"> <nif>nif1</nif> <nombre>nombre1</nombre> <direccion> calle 1</direccion> <poblacion>pueblo1</poblacion> <telefono> 23 </telefono> </persona> <persona codigo="c2"> <nif>nif2</nif> <nombre>nombre2</nombre> <direccion>calle 2</direccion> <poblacion>pueblo1</poblacion> <telefono>33 </telefono> </persona> <persona codigo="c3"> <nif>nif3</nif> <nombre>nombre3</nombre> <direccion>calle 3</direccion> <poblacion>pueblo2</poblacion> <telefono>34 </telefono> </persona> <persona> <nif>nif4</nif> <nombre>nombre4</nombre> <direccion>calle 4</direccion> <poblacion>pueblo2</poblacion> <telefono>34 </telefono> </persona> <persona> <nif>nif5</nif> <nombre> nombre5</nombre> <direccion> calle 5</direccion> <poblacion>pueblo3 </poblacion> <telefono> 45 </telefono> </persona> <persona> <nif>nif6</nif> <nombre> nombre6</nombre> <direccion> calle 6</direccion> <poblacion>pueblo3 </poblacion> <telefono> 15 </telefono> </persona> </personas>
y veamos cmo obtener el sumario con el nif y nombre de cada persona, cosa que podemos hacer mediante: <resumenPersonas> { for $persona in doc("personas.xml")/personas/persona return <resumenPersona> { string($persona/nif)} --- {string($persona/nombre)} </resumenPersona>
Enrique Mora Moral. Pag: 10/40
} </resumenPersonas> Generando el siguiente resultado <?xml version="1.0" encoding="UTF-8"?> <resumenPersonas> <resumenPersona>nif1 --- nombre1</resumenPersona> <resumenPersona>nif2 --- nombre2</resumenPersona> <resumenPersona>nif3 --- nombre3</resumenPersona> <resumenPersona>nif4 --- nombre4</resumenPersona> <resumenPersona>nif5 --- nombre5</resumenPersona> <resumenPersona>nif6 --- nombre6</resumenPersona> </resumenPersonas> donde se observa cmo tras la etiqueta de inicio del elemento se crea la variable $persona a la que se asigna una secuencia de nodos con el uso de la palabra clave in que precede al documento que proporciona esta secuencia, terminando con /personas/persona que selecciona cualquier elemento Capitulo del documento objeto de la consulta. Por su parte, la sentencia return define la salida para cada nodo que aparece en la secuencia definida por la variable $persona.
Los tipados (uso de tipos xs, xsd) con Esquemas o Relax NG, lo que supone contar con un lenguaje de consulta con datos estticos fuertemente tipados, lo que evita un gran nmero de errores. Los gobernados por otros lenguajes de esquema como DTDs. Los usados con una visin procedente de otro sistema no XML, como sera el caso de un Sistema de Gestin de Base de Datos relacional.
Obsrvese que las fuentes de datos pueden tener estructuras muy complejas, y por ello las expresiones deben estar bien definidas para que se est en condiciones de poder evaluar cualquier estructura. Por ello, XQuery se especific para trabajar con datos poco o muy tipados, siendo su sistema de tipos uno de sus aspectos ms tiles, eclcticos e inusuales que existen. Como conclusin, retngase que para encarar esta variedad de situaciones, XQuery permite escribir consultas con muy poca informacin sobre tipos. Ello es factible gracias a la capacidad de XQuery para obtener y utilizar la informacin de tipos en tiempo de ejecucin, siendo capaz, a pesar de ello, de poder detectar posibles errores antes de que la consulta se ejecute del todo. Si el documento XML manejado obedece slo a una DTD o incluso si carece de cualquier esquema,
Enrique Mora Moral. Pag: 11/40
los tipos son muy reducidos: documento, elemento, ID, IDREF, etc., con lo que el documento incorpora poca informacin referida a tipos, y por ello las consultas se hacen confiando en un conjunto de reglas, de tal manera que durante el proceso de ejecucin se pueda inferir el tipo apropiado para poder obtener el valor buscado. En cambio, cuando XQuery se enfrenta con tipos de datos derivados de Esquemas XML, debe distinguir mucho ms, y en con-secuencia debe estar en condiciones de manejar, por un lado, los tipos predefinidos accesibles en toda consulta, y por otro, los tipos importados para la consulta desde un Esquema especfico. Esta flexibilidad de XQuery debe ser apreciada debidamente.
El manejo de los rboles de XQuery. La combinacin y reestructuracin de los documentos XML obtenidos. Los cuantificadores, operadores y funciones propias de XQuery.
Pag: 12/40
Como ejemplo de referencia de este proceso usaremos el documento personas.xml incluido en el apartado 4.1 de esta unidad. Con la siguiente estructura:
<?xml version="1.0" encoding="UTF-8"?> <!ELEMENT personas (persona)* > <!ELEMENT persona (nif, nombre, direccion, poblacion, telefono) > <!ELEMENT nif (#PCDATA) > <!ELEMENT nombre (#PCDATA) > <!ELEMENT direccion (#PCDATA) > <!ELEMENT poblacion (#PCDATA) > <!ELEMENT telefono (#PCDATA) > <!ATTLIST persona edad CDATA #IMPLIED > <!ATTLIST persona codigo ID #IMPLIED >
doc("personas.xml") /personas/persona[nif="nif1"] que devuelve slo aquellas personas que tengan como nif el valor nif1 doc("personas.xml") /personas/persona[3] devuelve la tercera persona de mi lista
En la lnea de las expresiones XPath, una expresin en XQuery puede empezar con / o //. En el primer caso la bsqueda se inicia en el nodo raz, mientras que el significado del operador //, en
Enrique Mora Moral. Pag: 13/40
trminos del modelo de datos, es dar acceso a todos los atributos y descendientes de los nodos que aparecen en su izquierda en el documento considerado; por ejemplo:
doc ( "personas.xml" ) //nombre cualquier nombre del sistema. doc (" libros . xml" ) / / @edad elementos que tenga definido el atributo edad.
Igual que en XPath, las wildcards permiten que las consultas seleccionen sin especificar sus nombres completos; por ejemplo: doc("personas.xml")//persona[4]/* obtiene los elementos/etiquetas una a una de la cuarta persona, est o no en el espacio de nombres, ya que las expresiones XQuery soportan espacios de nombres, lo que permite distinguir nombres procedentes de vocabularios diferentes. Hagamos notar que debido a que durante el proceso de evaluacin de toda expresin XQuery siempre se devuelven nodos del documento sealado, si en ella hubiera algo que no correspondiera a uno de estos nodos aparecer un error de tipo.
</ejemplo> produce el documento: <?xml version="1.0" encoding="UTF-8"?> <ejemplo> <p> Esta es una consulta </p> <eg> doc("personas.xml")//persona[1]/nombre </eg> <p> Este es el resultado de la consulta anterior.</p> <eg> <nombre>nombre1</nombre> </eg> </ejemplo> El primer doc("personas.xml")//persona[1]/nombre se comporta como una constante, mientras que el segundo es sustituido por el resultado de evaluar la expresin anterior. Las expresiones incluidas en los constructores de elementos permiten crear nuevos valores XML reestructurando los existentes, como vamos a contar el numero de personas de nuestro fichero: <numero> {count(doc("personas.xml")/personas/persona)} </numero> se obtiene el documento: <?xml version="1.0" encoding="UTF-8"?> <numero>6</numero> Debe hacerse notar, aunque no mostremos ningn ejemplo, la posibilidad existente de enlazar constructores de forma sucesiva, creando con ello constructores sucesivamente ms complejos que van anidando elementos y atributos.
Extraccin de tipos
En un lenguaje de bsqueda, los tipos de datos permiten comprobar la correccin tanto de la propia consulta como de las operaciones a los que se va a someter los datos de la respuesta; en base a ello, XQuery aprovecha que los Esquemas XML proporcionen un conjunto de tipos predefinidos y la posibilidad de definir nuevos tipos para manejar los tipos de datos involucrados en una consulta. Por ello, en el prlogo de toda consulta deben figurar explcitamente los Esquemas que se van a importar, identificndolos por su espacio de nombres, de forma que durante el correspondiente proceso de validacin los nodos elemento y atributo puedan adquirir sus notaciones de tipo correspondientes. Recordemos que en el caso de que no se usen Esquemas, todos los nodos elemento tienen por defecto como notacin tipo xs:anyType. La consecuencia a retener es que la falta de definicin de tipos no impide que se puedan efectuar consultas con XQuery; por ejemplo: <media> {avg( doc("personas.xml")/persona/persona/telefono )} </media> calcula el valor medio de la etiqueta telefono en nuestro ejemplo, aunque no hayamos usado un Esquema o Relax sino un DTD, y el elemento telefono no esta bien tipado. Para que ello sea
Enrique Mora Moral. Pag: 15/40
posible, cuando avg() requiere un argumento numrico, automticamente cada valor de telefono se convierte a doble precisin y se calcula la media requerida. Esta conversin implcita siendo muy til cuando se trabaja con datos no tipados puede no ser ptima, como en el caso del ejemplo que se acaba de ver, donde el precio se representara mucho mejor por un decimal. Obviamente, si en el proceso de consulta existiese un Esquema que declarase telefono un campo peso como decimal, la media se calculara usando nmeros decimales. Consecuencia de lo anterior es la necesidad de conocer la forma como XQuery trata las distintas casusticas que pueden aparecer durante el procesado de un documento. As, por ejemplo, si nos encontramos con una expresin como: 1 * $b, hay que preguntarse cmo se interpretara si $b adoptara las distintas posibilidades existentes (por ejemplo que fuera una secuencia vaca, o un dato de caracteres sin tipar o un elemento, o una secuencia de cinco nodos, etc.). Este tipo de cuestiones es bsico que puedan resolverse, debido a la propia flexibilidad del XML, lo que obliga a que casos como stos deben quedar bien definidos a lo largo del proceso de consulta. Para hacer frente a esta necesidad, en XQuery existe una operacin bsica llamada extraccin de tipo, cuyo significado es evidente. Este proceso de extraccin de tipo permite que tengan sentido expresiones como: doc("personas.xml")/personas/personas/[nombre='nombre1'] donde siendo nombre un elemento y `nombre1' una cadena, se pueda asumir que pueden ser iguales. La clave reside en que el operador = extrae el tipo de valor del elemento, obteniendo que es una cadena, lo que permite a XQuery poderla comparar con 'nombre1' y tomar la decisin que corresponda. En lnea con lo anterior, adelantemos que XQuery incorpora la funcin data() que extrae directamente el tipo del valor correspondiente; por ejemplo: <resultado> {data( <e xsi:type="xs:integer">4</e> )} </resultado> una vez validado hace que se obtenga directamente como resultado el entero 4, sin tener que preocuparse del tipo de dato concreto. <?xml version="1.0" encoding="UTF-8"?> <resultado>4</resultado> En este proceso se esta evaluando al tirn el cdigo XML que se encuentra dentro de la funcin data. Lo normal es que se evale una variable que contiene una etiqueta.
Veamos lo que ocurre en el caso del elemento precio, segn el tipado que incorpore el operador (por simplicidad adelantamos el uso de dos de ellos, de evidente significado eq y gt):
Si se carece de tipo, se trata como una cadena y en consecuencia slo puede compararse con otra cadena. Este sera el caso de la consulta: for $b in doc("personas.xml")//persona where $b/poblacion eq "pueblo1"
Pag: 16/40
return $b/nombre
Si los datos dependen de una DTD, no se pueden usar los tipos simples de los Esquemas, con lo que el telefono no tiene tipo. Por ello en la siguiente consulta, es necesario pasar telefono a decimal: for $b in doc("personas.xml")//persona where xs:decimal($b/telefono) gt 33.00 return $b/nombre Devolviendo: <?xml version="1.0" encoding="UTF-8"?> <nombre>nombre3</nombre> <nombre>nombre4</nombre> <nombre> nombre5</nombre>
Si quien gobierna los tipos es un Esquema que declara telefono para ser un decimal, nada de lo anterior es necesario.
Como norma general en XQuery, los datos objeto de consulta se interpretan como datos tipados, y se fuerza a la consulta a tenerlos que interpretar antes de compararlos, con la nica excepcin de que sean cadenas o que efectivamente contengan los tipos adecuados. El hecho de que los Esquemas tengan tipos predefinidos permite usarlos para escribir funciones similares a las de los lenguajes de programacin convencionales, aprovechando las estructuras de XML. Como ejemplo, una funcin que eleva al cuadrado los telefonos: declare function local:cuadrado ($p as xs:integer) as xs:integer {$p * $p}; for $telefono in doc("personas.xml")//telefono return <cuadrado> {local:cuadrado ($telefono)} </cuadrado> de forma que la expresin $e/.. del documento instancia ser cierto cuando se evale para este nodo. A pesar de lo dicho, la posibilidad de trabajar con datos poco tipados en ocasiones es una ventaja no despreciable que el buen uso de XQuery puede explotar. Como ejemplo, adelantndonos a secciones siguientes, consideremos el caso de una funcin que devuelva una secuencia de tems en el orden inverso al existente en el documento, una situacin en la que parece razonable que no se especifique ni el tipo del parmetro de la funcin, ni el tipo que ser devuelto, ya que es razonable que esta funcin pueda aplicarse a cualquier secuencia de tems; por ejemplo: declare function local:reverse($items) { let $count := count($items) for $i in 0 to $count return $items[$count - $i] }; let $persona := doc("personas.xml")/personas/persona return local:reverse($persona)
Pag: 17/40
el operador to genera sucesiones de persona girandolas con la funcin reverse. Al no especificar ningn tipo, ni para los parmetros ni para el resultado, podra usarse para devolver una secuencia de cualquier otro tipo de datos.
Clusulas FLWOR
Se llama tupla a una combinacin de variables asociadas a una expresin FLWOR formada por las clusulas for o/y let, seguidas por where o/y order y obligatoriamente por return, ya que invariablemente algo se devuelve como consecuencia de una consulta; por ejemplo: for $b in doc("personas.xml")/personas/persona where $b/@edad = 25 return $b/nombre devuelve las personas cuya edad es 25, asociando la variable $b a cada persona para crear una serie de tuplas. En este ejemplo where comprueba si $b/@edad es igual a 25 de forma que return se evala para cada tupla que satisfaga la condicin. El resultado que se obtiene es: <?xml version="1.0" encoding="UTF-8"?> <nombre>nombre1</nombre> Las clusulas for y let Toda expresin FLWOR incorpora al menos una de estas clusulas, existiendo distintas combinaciones posibles para ellas. As en: for $i in (1, 2, 3) return <tupla><i>{ $i }</i></tupla> se crea un elemento tupla donde $i se asocia a (1, 2, 3) para construir una sucesin de enteros, dando como resultado: <?xml version="1.0" encoding="UTF-8"?> <tupla> <i>1</i>
Enrique Mora Moral. Pag: 18/40
</tupla> <tupla> <i>2</i> </tupla> <tupla> <i>3</i> </tupla> En cambio la clusula let asocia una variable al resultado global de una expresin y si no existen en ella ninguna clusula for, se crea una sola tupla. Si en el anterior se usa let en lugar de for, esto es: let $i := (1, 2, 3), el resultado es una nica tupla, donde la variable $i est limitada a la secuencia entera de enteros: let $i := (1, 2, 3) return <tupla> {$i} </tupla> Con el siguiente resultado: <?xml version="1.0" encoding="UTF-8"?> <tupla>1 2 3</tupla> Cuando let se usa en combinacin con una o ms clusulas for, las variables asociadas a let se aaden a las tupas generadas por las clusulas for; por ejemplo: for Si in (1, 2, 3) let $j := (1, 2, 3) return <tupla><i>{ Si }</i><j>{ $j }</j></tupla> obtiene como resultado: <tupla><i>1</i><j>1 2 3</j></tupla> <tupla><i>2</i><j>1 2 3</j></tupla> <tupla><i>3</i><j>1 2 3</j></tupla> En el siguiente ejemplo se muestra la relacin entre let y return:
(: cada return debe completar un cdigo XML valido :) (: se puede engaar devolviendo en una funcin una lista de nodos :) declare function local:clientes ($p1) { let $cliente := doc("facturacion.xml")/facturacion/clientes/cliente[nif = $p1] return (<td> {$cliente/nif} </td> , <td> {$cliente/nombre} </td>)}; <html> <body> {for $factura in doc("facturacion.xml")/facturacion/facturas/factura let $c3 := doc("facturacion.xml")/facturacion/clientes/cliente[nif = $factura/nif] return <table> <tr> <td> {string($factura/numero)} </td> <td> {string($factura/fecha)} </td></tr> <!-- la variable y es global dentro de todo el buble mostrando los valores de forma correcta permite mezclas con factura recomendacin --> <tr> <td> {$c3/nif} </td> <td> {$c3/nombre} </td> </tr> <tr> <td> {$factura/nif} </td> <td> {$c3/nombre} </td> </tr> <!-- engao con una funcin que devuelve una lista de nodos de dificil utilidad--> <tr> {local:clientes (string($factura/nif))} </tr>
Enrique Mora Moral. Pag: 19/40
<!-- Declaracin de la variable donde se cierra y se abre una elemento dentro del bucle en casos concretos, funciona como una funcin --> <tr> {let $c2 := doc("facturacion.xml")/facturacion/clientes/cliente[nif = $factura/nif] return ( <td> {$c2/nif} </td> , <td> {$c2/nombre} </td> ) } </tr> </table>} </body> </html>
La clusula where Esta clusula elimina las tupas que no satisfacen una determinada condicin, de forma que return slo se evala para aquellas personas cuya edad supere los 25 aos. Quedando: for $p in doc("personas.xml")/personas/persona where $p/@edad > 25 return $p
d ando
Podemos consultar las personas que no incluyen el atributo edad. for $p in doc("personas.xml")/personas/persona where not($p/@edad ) return $p Aunque su anlogo en SQL WHERE slo comprueba valores simples, esta restriccin no se da en XQuery, donde la clusula where puede contener cualquier expresin que se evale a un valor booleano. Aunque sea una expresin compleja sobre los sug-elementos de un objeto.
La clusula order
Esta clusula ordena las tupas antes de evaluar return, con el objeto de poder cambiar el orden del resultado. As, para ordenar alfabticamente las personas por nombre en orden descendente se puede escribir: for $p in doc("personas.xml")/personas/persona order by $p/nombre descending return $p Por defecto se considera orden ascendente y se pueden mezclar varios ordenes de forma arbitraria: for $p in doc("personas.xml")/personas/persona order by $p/nombre descending, $p/@edad, $p/poblacion descending return $p
La clusula return
Enrique Mora Moral. Pag: 20/40
Esta clusula est en toda expresin FLWOR y tambin es comn en los elementos constructores. As por ejemplo, la siguiente consulta reduce nuestro fichero de personas al nif y el nombre eliminando el resto de los elementos: <personas> {for $p in doc("personas.xml")/personas/persona return <persona> { $p/nif, $p/nombre } </persona> } </personas> el resultado que se obtiene es: <?xml version="1.0" encoding="UTF-8"?> <personas> <persona> <nif>nif1</nif> <nombre>nombre1</nombre> </persona> <persona> <nif>nif2</nif> <nombre>nombre2</nombre> </persona> <persona> <nif>nif3</nif> <nombre>nombre3</nombre> </persona> <persona> <nif>nif4</nif> <nombre>nombre4</nombre> </persona> <persona> <nif>nif5</nif> <nombre> nombre5</nombre> </persona> <persona> <nif>nif6</nif> <nombre> nombre6</nombre> </persona> </personas> Existen una gran variedad de aplicaciones del uso de los constructores de elementos con una clusula return. Por ejemplo, la tarea de insertar un elemento direccin que mezcle los campos direccin y poblacin en una nica etiqueta: <personas> {for $p in doc("personas.xml")/personas/persona return <persona> { $p/nif, $p/nombre } <direccion> {concat(data($p/direccion), data($p/poblacion))} </direccion></persona> } </personas>
Pag: 21/40
la consulta tiene como resultado: <?xml version="1.0" encoding="UTF-8"?> <personas> <persona> <nif>nif1</nif> <nombre>nombre1</nombre> <direccion> calle 1pueblo1</direccion> </persona> <persona> <nif>nif2</nif> <nombre>nombre2</nombre> <direccion>calle 2pueblo1</direccion> </persona> <persona> <nif>nif3</nif> <nombre>nombre3</nombre> <direccion>calle 3pueblo2</direccion> </persona> <persona> <nif>nif4</nif> <nombre>nombre4</nombre> <direccion>calle 4pueblo2</direccion> </persona> <persona> <nif>nif5</nif> <nombre> nombre5</nombre> <direccion> calle 5pueblo3 </direccion> </persona> <persona> <nif>nif6</nif> <nombre> nombre6</nombre> <direccion> calle 6pueblo3 </direccion> </persona> </personas> Podemos separar direccin de poblacin o incluso meter la poblacin entre parntesis basta con: <personas> {for $p in doc("personas.xml")/personas/persona return <persona> { $p/nif, $p/nombre } <direccion> {concat(data($p/direccion), " (", data($p/poblacion),")")} </direccion></persona> } </personas>
Expresiones condicionales
En XQuery se utilizan expresiones condicionales de la misma forma que en otros lenguajes, por lo que aparece en XQuery tanto la clusula if como then y else. Comenzamos modificando nuestro fichero de personas con la siguiente estructura: <?xml version="1.0" encoding="UTF-8"?> <!ELEMENT personas (persona)* >
Enrique Mora Moral. Pag: 22/40
<!ELEMENT persona (nif, nombre, direccion, poblacion, telefono,gastos) > <!ELEMENT nif (#PCDATA) > <!ELEMENT nombre (#PCDATA) > <!ELEMENT direccion (#PCDATA) > <!ELEMENT poblacion (#PCDATA) > <!ELEMENT telefono (#PCDATA) > <!ELEMENT gastos (gasto)* > <!ELEMENT gasto (fecha, valor) > <!ELEMENT fecha (#PCDATA) > <!ELEMENT valor (#PCDATA)> <!ATTLIST persona edad CDATA #IMPLIED > <!ATTLIST persona codigo ID #IMPLIED > Sobre esta estructura modificamos nuestros datos, ajustando los gastos de estas personas:
<?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="text/xsl" href="hoja1.xsl"?> <!DOCTYPE personas SYSTEM "file:/media/Datos/Curso11-12/proyecto1/personas.dtd"> <personas> <persona edad="25"> <nif>nif1</nif> <nombre>nombre1</nombre> <direccion> calle 1</direccion> <poblacion>pueblo1</poblacion> <telefono> 23 </telefono> </persona> <persona codigo="c2"> <nif>nif2</nif> <nombre>nombre2</nombre> <direccion>calle 2</direccion> <poblacion>pueblo1</poblacion> <telefono>33 </telefono> <gastos> <gasto> <fecha>2012-01-01</fecha> <valor>100</valor> </gasto> <gasto> <fecha>2012-02-01</fecha> <valor>200</valor> </gasto> </gastos> </persona> <persona codigo="c3"> <nif>nif3</nif> <nombre>nombre3</nombre> <direccion>calle 3</direccion> <poblacion>pueblo2</poblacion> <telefono>34 </telefono> <gastos> <gasto> <fecha>2012-01-01</fecha> <valor>300</valor> </gasto> </gastos>
Enrique Mora Moral. Pag: 23/40
</persona> <persona> <nif>nif4</nif> <nombre>nombre4</nombre> <direccion>calle 4</direccion> <poblacion>pueblo2</poblacion> <telefono>34 </telefono> <gastos> <gasto> <fecha>2012-01-01</fecha> <valor>400</valor> </gasto> </gastos> </persona> <persona> <nif>nif5</nif> <nombre> nombre5</nombre> <direccion> calle 5</direccion> <poblacion>pueblo3 </poblacion> <telefono> 45 </telefono> <gastos> <gasto> <fecha>2012-01-01</fecha> <valor>500</valor> </gasto> </gastos> </persona> <persona> <nif>nif6</nif> <nombre> nombre6</nombre> <direccion> calle 6</direccion> <poblacion>pueblo3 </poblacion> <telefono> 15 </telefono> <gastos> </gastos> </persona> </personas>
Como ejemplo podemos obtener consultas complejas, como personas que tengan ms de dos gastos. for $p in doc("personas.xml")/personas/persona where $p/gastos/count(gasto) >= 2 return $p como resultado sale:
<?xml version="1.0" encoding="UTF-8"?> <persona codigo="c2"> <nif>nif2</nif> <nombre>nombre2</nombre> <direccion>calle 2</direccion> <poblacion>pueblo1</poblacion> <telefono>33 </telefono> <gastos> <gasto> <fecha>2012-01-01</fecha> <valor>100</valor> </gasto> <gasto> <fecha>2012-02-01</fecha>
Enrique Mora Moral. Pag: 24/40
No es una sentencia condicional, pero aprovechando el count anterior puedo aadir una etiqueta <numeroDeGastos> al nif y al nombre de las personas que tengan dos gastos o ms. (>= 2): <personas> { for $p in doc("personas.xml")/personas/persona return <persona> {$p/nif, $p/nombre} { if ($p/gastos/count(gasto) >= 2) then <numeroDeGastos> {$p/gastos/count(gasto)} </numeroDeGastos> else () } </persona> } </personas> donde la secuencia vaca () se usa para especificar que una clusula no devuelve nada. El resultado que se obtiene es:
<?xml version="1.0" encoding="UTF-8"?> <personas> <persona> <nif>nif1</nif> <nombre>nombre1</nombre> </persona> <persona> <nif>nif2</nif> <nombre>nombre2</nombre> <numeroDeGastos>2</numeroDeGastos> </persona> <persona> <nif>nif3</nif> <nombre>nombre3</nombre> </persona> <persona> <nif>nif4</nif> <nombre>nombre4</nombre> </persona> <persona> <nif>nif5</nif> <nombre> nombre5</nombre> </persona> <persona> <nif>nif6</nif> <nombre> nombre6</nombre> </persona> </personas>
Otro ejemplo, es el cambio del color de fondo en la cabecera de una tabla, aplicando la sentencia IF al valor del atributo BGColor:
<table> <tr bgcolor="{if ($factura/numero mod 2 = 0) then ("blue") else ("red") }"> <td> numero </td> <td> fecha </td> </tr>
Operar en XQuery
Enrique Mora Moral. Pag: 25/40
Aunque ya han sido utilizadas en algunos casos, veamos de forma ms sistemtica las piezas con las que se elaboran las consultas Xquery.
Cuantificadores
Para las consultas basadas en una condicin resulta bsico determinar tanto si existe al menos un tem que la satisfaga, como saber si todos los tems involucrados en ella lo hacen; ste es el mbito respectivo de los cuantificadores existencial y universal. Consideremos la consulta: for $p in doc("personas.xml")/personas/persona where some $g in $p/gastos/gasto satisfies ($g/valor > 400) return $p en ella, el cuantificador existencial some incluido en la clusula where se encarga de comprobar si existe al menos un gasto de una persona superior a 400. El resultado obtenido es la quinta persona con que presenta un gasto de 500:
<?xml version="1.0" encoding="UTF-8"?> <persona> <nif>nif5</nif> <nombre> nombre5</nombre> <direccion> calle 5</direccion> <poblacion>pueblo3 </poblacion> <telefono> 45 </telefono> <gastos> <gasto> <fecha>2012-01-01</fecha> <valor>500</valor> </gasto> </gastos> </persona>
Otra cosa es que el total de los gastos de una persona superar los 400. En este caso sera algo parecido a: for $p in doc("personas.xml")/personas/persona where sum ($p/gastos/gasto/valor) > 400 return $p En este caso devuelve el mismo valor, pero la consulta anterior es distinta a la que utiliza la clausula exist. El el primer caso busca la existencia de un gasto individual superior a 400, en el segundo busca que el total de sus gasto supere a 400. Por su parte, un cuantificador universal tiene la funcin de comprobar si todos los nodos de una determinada secuencia satisfacen la condicin objeto de la consulta. Por ejemplo, podemos seleccionar aquellas personas en las que cada uno de sus gastos supera los 200. for $p in doc("personas.xml")/personas/persona where every $g in $p/gastos/gasto satisfies ($g/valor > 200) return $p
Enrique Mora Moral. Pag: 26/40
Pag: 27/40
El operador every reconocido en lgica con all (todos), funciona correctamente y escoge la persona si todos sus gastos superan los 200. Presenta un problema, si no hay ningn gasto devuelve el valor verdadero, por eso aparece nif6 y nif1. Existe una relacin entre el operador all o (every) y el operador exist o (some). Estas reglas de la lgica son una ampliacin de las Leyes de Morgan sobre la negacin. x[condicin] = ~x[~condicin] x[condicin] = ~x[~condicin]
Operadores
En su mayora los operadores que se utilizan en XQuery coinciden con los habituales en el resto de lenguajes de programacin; los ms utilizados son los siguientes: Aritmticos: +, -, *, div, idiv, mod, todos con su significado convencional. Comparativos: tambin se corresponde con los operadores habituales conocidos: eq =, ne !=, lt <, le <=, gt >, ge >=. Debe sealarse que tanto estos operadores comparativos como los aritmticos, cuando se enfrentan a secuencias vacas, actan de la misma forma que SQL lo hace con los null. De posicin: XQuery proporciona dos operadores para determinar la posicin de dos nodos en el orden propio de un documento, que son tiles cuando por alguna razn el orden de los elementos sea significativo. El operador $a << $b devuelve cierto si $a precede a $b en el orden del documento y viceversa con $a >> $b. Ejemplo: for $p in doc("personas.xml")/personas/persona let $p4 := doc("personas.xml")/personas/persona[4] return if ($p >> $p4) then $p else () Con: let $p4 := doc("personas.xml")/personas/persona[4] Selecciono la cuarta persona de la lista de personas. Y: if ($p >> $p4) then $p else () Selecciono aquellas personas que estn detrs de esta cuarta persona. Resultando:
<?xml version="1.0" encoding="UTF-8"?> <persona> <nif>nif5</nif> <nombre> nombre5</nombre> <direccion> calle 5</direccion> <poblacion>pueblo3 </poblacion> <telefono> 45 </telefono> <gastos> <gasto> <fecha>2012-01-01</fecha> <valor>500</valor> </gasto>
Enrique Mora Moral. Pag: 28/40
</gastos> </persona> <persona> <nif>nif6</nif> <nombre> nombre6</nombre> <direccion> calle 6</direccion> <poblacion>pueblo3 </poblacion> <telefono> 15 </telefono> <gastos> </gastos> </persona>
De Secuencia: estos operadores actan combinando secuencias para obtener como resultado otra secuencia, sin cambiar el orden interno que stas tenan en el documento original; son stos: union, intersect, y except. Los operadores union (que tambin admite la forma lxica: | ) e intersect equivalen a las correspondientes operaciones conjuntistas, aunque ahora con secuencias de operandos. El operador except, parte de dos secuencias de nodos y devuelve otra con todos los nodos presentes en el primer operando que no figuran en la segunda. Debe sealarse que se pueden combinar estos operadores de secuencia, siempre que se mantenga el principio de que ningn nodo aparezca dos o ms veces. En el caso de que algn operando involucrado en estas operaciones contenga un tem que no sea un nodo se declara el error correspondiente. Ejemplo de union: for $p in doc("personas.xml")/personas/persona[1] union doc("personas.xml")/personas/persona[2] return $p Donde selecciono la primera y la segunda persona. Ejemplo de intersect o interseccin. Por ejemplo, personas de pueblo1 con el atributo edad: for $p in doc("personas.xml")/personas/persona[poblacion="pueblo1"] intersect doc("personas.xml")/personas/persona[@edad] return $p En este caso devuelve:
<?xml version="1.0" encoding="UTF-8"?> <persona edad="25"> <nif>nif1</nif> <nombre>nombre1</nombre> <direccion> calle 1</direccion> <poblacion>pueblo1</poblacion> <telefono> 23 </telefono> <gastos/> </persona>
Que corresponde con el nico elemento que pertenece a los dos conjuntos. Ejemplo de execpt o diferencia. Son los elementos que estn en el primer grupo y no estn en el segundo. Por ejemplo: for $p in doc("personas.xml")/personas/persona[poblacion="pueblo1"] except doc("personas.xml")/personas/persona[@edad] return $p
Enrique Mora Moral. Pag: 29/40
Son las personas de pueblo1 no tienen definida la edad. En este caso devuelve:
<?xml version="1.0" encoding="UTF-8"?> <persona codigo="c2"> <nif>nif2</nif> <nombre>nombre2</nombre> <direccion>calle 2</direccion> <poblacion>pueblo1</poblacion> <telefono>33 </telefono> <gastos> <gasto> <fecha>2012-01-01</fecha> <valor>100</valor> </gasto> <gasto> <fecha>2012-02-01</fecha> <valor>200</valor> </gasto> </gastos> </persona>
Funciones predefinidas
En XQuery existen todo un conjunto de funciones predefinidas muchas de las cuales son habituales en otros lenguajes y otras estn pensadas especficamente para procesar XML. Como en SQL son muy usadas funciones tales como: mino, max(), coun(), sum(), avg(), etc., cuyo significado, parmetros y resultados son suficientemente evidentes. Otras funciones familiares de XQuery son las que operan sobre nmeros: round(), floor() y ceiling(), y sobre cadenas: concat(), string-length(), starts-with(), ends-with(), substring(), uppercase(), lower-case() que incluso pueden adaptarse para admitir como parmetros distintos tipos de datos simples. Respecto a las funciones propias de XML que no suelen estar en otros lenguajes, algunas de ellas ya las hemos definido y utilizado como es el caso de doc(). En este grupo son especialmente usadas: not(), empty() y exists(). La primera tiene el correspondiente significado booleano basado en negacin; empty() es una funcin que detecta si una secuencia es vaca; la funcin opuesta es exists(), que indica si una secuencia contiene al menos un tem. Adems de las citadas, hay que destacar aquellas funciones que acceden a tipos de informacin de un nodo, como string() que devuelve el valor de cadena de un nodo o la ya utilizada data(), que devuelve el tipo del valor del nodo. Ms especficamente, el valor de string() incluye la representacin del texto encontrado en el nodo y sus descendientes, concatenndolos segn el orden de aparicin en el documento; por ejemplo: string((doc("personas.xml")/personas/persona[1])) da como resultado la cadena el siguiente texto:
<?xml version="1.0" encoding="UTF-8"?> nif1 nombre1 calle 1 pueblo1 23
Enrique Mora Moral. Pag: 30/40
Para finalizar, es importante sealar que en XQuery es perfectamente posible crear funciones definidas por el usuario, construidas sobre la biblioteca bsica que proporciona el lenguaje. En particular estas funciones definidas por el usuario permiten abreviar consultas muy largas. Esta posibilidad de recurrir a XQuery desde otros lenguajes hace que las implementaciones XQuery forme parte de entornos de programacin basados en Java o C#, o incluso de sistemas de gestin de bases de datos relacionales, de forma que este entorno proporciona a XQuery tanto funciones externas como variables. El desarrollo de XQuery es uno de los ms laboriosos, pues depende de mltiples circunstancias, y debe tener en cuenta una gran cantidad de requisitos. Lo presentado en este captulo es slo una introduccin a estos puntos, con el objetivo de poner de manifiesto los problemas a los que se tiene que enfrentar la nueva Web para alcanzar todas sus posibilidades. A lo anterior hay que aadir el propio problema del desarrollo de Sistemas de Gestin de Bases de Datos que manejen documentos XML, un tema al cual nos referiremos brevemente en el ltimo captulo. pero que por el momento no forma parte de la familia XML.
Pag: 31/40
Una vez cambiada la libera Saxon tengo que comprobar que existe una extensin de archivos xu asociados asociado al Editor Xquery, se comprueba desde la misma ventana anterior buscando File Types, como se puede comprobar en la siguiente ventana:
Adems de esto es preciso configurar y ajustar el escenario de ejecucin para Saxon EE. El escenario de ejecucin Xquery se configura desde el siguiente Icono: Desde este punto accedemos a la configuracin de los escenarios:
Pag: 32/40
Una vez hechos estos procesos podemos comenzar a modificar nuestros documentos XML desde una consulta Xquery. RENOMBRADO DE NODOS. Es posible renombrar un elemento o grupo de elementos determinados. Se le puede cambiar el nombre a un nodo con la sentencia rename. Por ejemplo, podemos cambiar la primera etiqueta <nif> de una persona por la etiqueta <cif> con la siguiente sentencia: rename node doc("personas.xml")/personas/persona[1]/nif as "cif" El contenido de la etiqueta <nif> se pasa integro a la etiqueta <cif> y se tendra que comprobar la descripcin del documento y los tipos de datos en el proceso de cambio de dicha etiqueta. Rename funciona nodo a nodo. Si se quiere cambiar todos los nif de personas por cif se utilizara el siguiente cdigo:
for $nif in doc("personas.xml")/personas/persona/nif return rename node $nif as "cif"
INSERCIN
Se quiera aadir un nuevo baile en la base de datos. Los datos son: La insercin se realizara de la siguiente manera: insert node <persona> <nif>nifnuevo</nif> <nombre>nombrenuevo</nombre> <direccion>calleNuevo</direccion> <poblacion>puebloNuevo</poblacion> <telefono>nuevo</telefono> <gastos> <gasto> <fecha>2012-01-01</fecha> <valor>100</valor> </gasto> </gastos> </persona> before doc("personas.xml")/personas/persona[1] Este cdigo inserta el nodo indicado en fichero personas.xml". El nodo se insertar antes del primer nodo de la base de datos (por la clausula "before"). Si se quiere insertar despus, solo cambiara "before" por "after". Ambas utilizan como referencia al primer nodo ("[1]"). Una sentencia equivalente para insertar al principio del fichero, sin tener que referenciar a nodo alguno de la base de datos, sera sustituyendo la ltima lnea por esta otra: insert node <persona> <nif>nifnuevo</nif> <nombre>nombrenuevo</nombre> <direccion>calleNuevo</direccion> <poblacion>puebloNuevo</poblacion> <telefono>nuevo</telefono> <gastos> <gasto> <fecha>2012-01-01</fecha> <valor>100</valor> </gasto> </gastos> </persona> as first into doc("personas.xml")/personas
Pag: 34/40
Cada vez que se pulsa una ejecucin introduce un nuevo elemento repetido, pasa exactamente lo mismo que con la sentencia insert en una base de datos. Si por el contrario, lo que se desea es insertar al final de la base de datos, sin referenciar a ningn nodo, se realizara de la siguiente manera: as last into doc("personas.xml")/personas Se puede incluso aadir una lista de nodos entre parntesis separados por comas:
insert node (<persona> <nif>nifnuevo1</nif> <nombre>nombrenuevo</nombre> <direccion>calleNuevo</direccion> <poblacion>puebloNuevo</poblacion> <telefono>nuevo</telefono> <gastos> <gasto> <fecha>2012-01-01</fecha> <valor>100</valor> </gasto> </gastos> </persona>, <persona> <nif>nifnuevo2</nif> <nombre>nombrenuevo</nombre> <direccion>calleNuevo</direccion> <poblacion>puebloNuevo</poblacion> <telefono>nuevo</telefono> <gastos> <gasto> <fecha>2012-01-01</fecha> <valor>100</valor> </gasto> </gastos> </persona>) before doc("personas.xml")/personas/persona[1]
O seleccionar una variable y aadirlos al lote o uno a uno en un bucle for. Por ejemplo, repetir los de pueblo1 usando una variable: let $clnPbl1 := doc("personas.xml")/personas/persona[poblacion ="pueblo1"] return insert node $clnPbl1 before doc("personas.xml")/personas/persona[1]
MODIFICACIN.
Pues resulta, que antes se insertaron de forma automtica varios nodos idnticos. Se va a proceder a cambiar el nif del primero cambiando nifnuevo por nif-n1 La modificacin se realizara de la siguiente manera:
replace value of node
Enrique Mora Moral. Pag: 35/40
Se pueden realizar varias modificaciones a la vez, separndolas por comas. Cambiamos el nif del primero a nif-n1c y el del segundo a nif-n2c:
replace value of node doc("personas.xml")/personas/persona[1]/nif with "nif-n1c", replace value of node doc("personas.xml")/personas/persona[2]/nif with "nif-n2c"
Replace no permite modificar un lista de nodos entre parntesis, para modificar varios nodos es necesario usar un bucle for. Por ejemplo, fijar todas las poblaciones a Antequera:
for $poblacion in doc("personas.xml")/personas/persona/poblacion return replace value of node $poblacion with "Antequera"
BORRADO
Despus aadir y modificar elementos, podemos borrarlos. Por ejemplo, se van a borrar la primera y la segunda persona: delete node doc("personas.xml")/personas/persona[1], delete node doc("personas.xml")/personas/persona[2] Cuidado con los borrados mltiples que pueden dejar el fichero vaco. Delete permite borrar listas de nodos, por lo que es posible ejecutar el siguiente cdigo para borrar todos los clientes de Archidona: let $archidona := doc("personas.xml")/personas/persona[poblacion = "Archidona"] return delete node $archidona Aunque, es ms cmodo declarar la variable en un bucle for y borrar nodo a nodo.
Pag: 36/40
Figura Exportacin de libreras XML en Qizx Para finalizar, se habl anteriormente de cmo utilizar expresiones FLWOR para que devuelvan cdigo HTML. El procedimiento para exportar los resultados es muy sencillo. Una vez que se est en la pestaa "XQuery" y se ejecuta la consulta, en la parte derecha muestra los resultados. Hay que pusar el botn de exportacin de resultados "Save results" y aparecer una ventana similar a la de la Figura anterior. De esta manera tendremos en fichero los resultados de la consulta.
tenga el proyecto al que vaya a implantarse, haciendo especial hincapi en el almacenamiento y el tratamiento de la informacin.
Donde podemos cargar los siguientes datos de prueba: Se pueden realizar las siguientes consultas Xpath: 1. Calcular el total de kilos de aceitunas que se han llevado a la cooperativa. /cooperativa/vales/sum(vale/peso) 2. Socios que tienen un saldo negativo y no han aportado aceitunas a la cooperativa. /cooperativa/socios/socio[saldo < 0 and not (@numeroSocio = /cooperativa/vales/vale/@numeroSocio)] 3. Mostrar vale o vales con el rendimiento ms alto de aceite en las aceitunas. /cooperativa/vales/vale[rendimiento = /cooperativa/vales/max(vale/rendimiento)] 4. Vales incorrectos. Son aquellos en los que no existe el socio, el peso es negativo o cero y el rendimiento no se encuentra entre 0 y 100. /cooperativa/vales/vale[rendimiento < 0 or rendimiento > 100 or peso < 0 or not(@numeroSocio = /cooperativa/socios/socio/@numeroSocio)]
Pag: 38/40
5. Mostrar los socios que se encuentran en la lista detrs del socio con nif4 /cooperativa/socios/socio[. >> /cooperativa/socios/socio[nif = "nif4"]] 6. Mostrar los socios que son de la misma poblacin que el socio con nif1. A priori no se conoce la poblacin de este individuo.(0.5) /cooperativa/socios/socio[poblacion = /cooperativa/socios/socio[nif="nif1"]/poblacion]
Pag: 39/40
3. Generar un documento valesSocios.xml nuevo que contenga los vales agrupados por socios con la siguiente estrucutura: <valesSocios> <socio numeroSocio=> <nif> </nif> <nombre> </nombre> <direccion> </direccion> <poblacion> </poblacion> <telefono> </telefono> <vales> <vale numeroVale = > <fecha> </fecha> <peso> </peso> <rendimiento> <rendimiento> <kilosAceite> </kilosAceite> </vale> <vales> <socios </valesSocios> Solucin:
<valesSocio> {for $socio in doc("cooperativa.xml")/cooperativa/socios/socio let $vales := doc("cooperativa.xml")/cooperativa/vales/vale[@numeroSocio = $socio/@numeroSocio] return <socio numeroSocio="{string($socio/@numeroSocio)}"> {$socio/nif} {$socio/nombre} {$socio/direccion} {$socio/poblacion} {$socio/telefono} <vales> {for $vale in $vales return <vale numeroVale="{string($vale/@numeroVale)}"> {$vale/fecha} {$vale/peso} {$vale/rendimiento} <kilosAceite> {$vale/peso * $vale/rendimiento div 100} </kilosAceite> </vale> } </vales></socio> } </valesSocio>
4. Sobre el documento anterior que se puede llamar sol3.xml mostrar un documento HTML donde aparezca nif, nombre del socio e importe total de sus aceitunas: <html> <body> <table border="3px"> <tr> <td> numeroSocio </td> <td> nif </td> <td> mombre </td> <td> Importe </td> </tr> { for $socio in doc("sol3.xml")/valesSocio/socio let $importe := $socio/sum(vales/vale/kilosAceite) * 1.5 return <tr> <td> {string($socio/@numeroSocio)} </td> <td> {string($socio/nif)} </td> <td> {string($socio/nombre)} </td> <td> {string($importe)} </td> </tr> } </table> </body> </html>
Pag: 40/40