En SQL:2006 se introdujeron revisiones significativas a las especificaciones relacionadas con XML en ISO/IEC 9075-14 (SQL/XML). La implementación en PostgreSQL del tipo de datos XML y las funciones relacionadas sigue en gran medida la edición anterior de 2003, con algunos préstamos de ediciones posteriores. En particular:
Donde el estándar actual proporciona una familia de tipos de datos XML
para albergar “document” (documento) o “content” (contenido)
en variantes sin tipo o con tipos XML Schema, y un tipo
XML(SEQUENCE) para albergar fragmentos arbitrarios de contenido XML,
PostgreSQL proporciona el único tipo
xml, que puede albergar tanto “document” como
“content”. No existe un equivalente para el tipo
“sequence” del estándar.
PostgreSQL proporciona dos funciones introducidas en SQL:2006, pero en variantes que utilizan el lenguaje XPath 1.0, en lugar de XML Query como se especifica para ellas en el estándar.
PostgreSQL no soporta las cláusulas
RETURNING CONTENT o RETURNING SEQUENCE;
las funciones que están definidas para tener estas en la especificación
devuelven implícitamente contenido.
Esta sección presenta algunas de las diferencias resultantes con las que te puedes encontrar.
Las funciones específicas de PostgreSQL
xpath() y xpath_exists()
realizan consultas en documentos XML utilizando el lenguaje XPath.
PostgreSQL también proporciona variantes exclusivas de XPath
de las funciones del estándar XMLEXISTS y
XMLTABLE, que oficialmente utilizan
el lenguaje XQuery. Para todas estas funciones,
PostgreSQL depende de la biblioteca
libxml2, que solo proporciona XPath 1.0.
Existe una fuerte conexión entre el lenguaje XQuery y las versiones de XPath 2.0 y posteriores: cualquier expresión que sea sintácticamente válida y se ejecute con éxito en ambos produce el mismo resultado (con una pequeña excepción para las expresiones que contienen referencias a caracteres numéricos o referencias a entidades predefinidas, que XQuery reemplaza con el carácter correspondiente mientras que XPath las deja tal cual). Pero no existe tal conexión entre estos lenguajes y XPath 1.0; este era un lenguaje anterior y difiere en muchos aspectos.
Hay dos categorías de limitaciones a tener en cuenta: la restricción de XQuery a XPath para las funciones especificadas en el estándar SQL, y la restricción de XPath a la versión 1.0 tanto para las funciones del estándar como para las específicas de PostgreSQL.
Las características de XQuery más allá de las de XPath incluyen:
Las expresiones XQuery pueden construir y devolver nuevos nodos XML, además de todos los valores posibles de XPath. XPath puede crear y devolver valores de los tipos atómicos (números, cadenas, etc.) pero solo puede devolver nodos XML que ya estaban presentes en los documentos suministrados como entrada de la expresión.
XQuery tiene constructores de control para iteración, ordenamiento y agrupación.
XQuery permite la declaración y uso de funciones locales.
Las versiones recientes de XPath comienzan a ofrecer capacidades que se superponen con
estas (como for-each y sort de estilo funcional,
funciones anónimas y parse-xml para crear un nodo a partir de una cadena),
pero estas características no estaban disponibles antes de XPath 3.0.
Para los desarrolladores familiarizados con XQuery y XPath 2.0 o posterior, XPath 1.0 presenta una serie de diferencias con las que lidiar:
El tipo fundamental de una expresión XQuery/XPath, la secuencia
(sequence), que puede contener nodos XML, valores atómicos o ambos, no
existe en XPath 1.0. Una expresión de la versión 1.0 solo puede producir un conjunto
de nodos (que contiene cero o más nodos XML) o un único valor atómico.
A diferencia de una secuencia de XQuery/XPath, que puede contener cualquier elemento deseado en cualquier orden deseado, un conjunto de nodos de XPath 1.0 no tiene un orden garantizado y, como cualquier conjunto, no permite múltiples apariciones del mismo elemento.
La biblioteca libxml2 parece devolver siempre conjuntos de nodos a PostgreSQL con sus miembros en el mismo orden relativo que tenían en el documento de entrada. Su documentación no se compromete con este comportamiento, y una expresión XPath 1.0 no puede controlarlo.
Mientras que XQuery/XPath proporciona todos los tipos definidos en XML Schema
y muchos operadores y funciones sobre esos tipos, XPath 1.0 solo tiene
conjuntos de nodos y los tres tipos atómicos boolean,
double y string.
XPath 1.0 no tiene operador condicional. Una expresión XQuery/XPath
como if ( hat ) then hat/@size else "no hat"
no tiene equivalente en XPath 1.0.
XPath 1.0 no tiene operador de comparación de orden para cadenas. Tanto
"cat" < "dog" y
"cat" > "dog" son falsos, porque cada uno es una
comparación numérica de dos NaN. Por el contrario,
= y != sí comparan las cadenas como cadenas.
XPath 1.0 difumina la distinción entre
comparaciones de valor y
comparaciones generales tal como las define
XQuery/XPath. Tanto sale/@hatsize = 7 y
sale/@customer = "alice" son comparaciones cuantificadas
existencialmente, verdaderas si hay algún sale con el
valor dado para el atributo, pero sale/@taxable = false()
es una comparación de valor respecto al
valor booleano efectivo de todo un conjunto de nodos.
Es verdadera solo si ningún sale tiene un atributo
taxable en absoluto.
En el modelo de datos de XQuery/XPath, un nodo de
documento puede tener forma de documento (es decir, exactamente un
elemento de nivel superior, con solo comentarios e instrucciones de procesamiento
fuera de él) o forma de contenido (con esas restricciones
relajadas). Su equivalente en XPath 1.0, el
nodo raíz, solo puede estar en forma de documento.
Esta es parte de la razón por la que un valor de tipo xml pasado como
elemento de contexto a cualquier función basada en XPath de PostgreSQL
debe estar en forma de documento.
Las diferencias señaladas aquí no son todas. En XQuery y las versiones 2.0 y posteriores de XPath, existe un modo de compatibilidad con XPath 1.0, y las listas del W3C de cambios en la biblioteca de funciones y cambios en el lenguaje aplicados en ese modo ofrecen un relato más completo (pero aún no exhaustivo) de las diferencias. El modo de compatibilidad no puede hacer que los lenguajes posteriores sean exactamente equivalentes a XPath 1.0.
En SQL:2006 y posteriores, ambas direcciones de conversión entre los tipos de datos SQL estándar y los tipos XML Schema se especifican de forma precisa. Sin embargo, las reglas se expresan utilizando los tipos y la semántica de XQuery/XPath, y no tienen aplicación directa al modelo de datos diferente de XPath 1.0.
Cuando PostgreSQL mapea valores de datos SQL a XML
(como en xmlelement), o XML a SQL (como en las columnas
de salida de xmltable), excepto por unos pocos casos
tratados especialmente, PostgreSQL simplemente asume
que la forma de cadena de texto de XPath 1.0 del tipo de datos XML será válida como la
forma de entrada de texto del tipo de datos SQL, y viceversa. Esta regla tiene la
virtud de la simplicidad a la vez que produce, para muchos tipos de datos, resultados similares
a los mapeos especificados en el estándar.
Cuando la interoperabilidad con otros sistemas sea una preocupación, para algunos tipos de datos puede ser necesario utilizar explícitamente funciones de formato de tipo de datos (como las de Section 9.8) para producir los mapeos del estándar.
Esta sección se refiere a los límites que no son inherentes a la biblioteca libxml2, sino que se aplican a la implementación actual en PostgreSQL.
El estándar SQL define dos mecanismos de paso (passing mechanisms)
que se aplican al pasar un argumento XML de SQL a una función XML o al recibir un
resultado: BY REF, en el que un valor XML particular conserva su identidad
de nodo, y BY VALUE, en el que se pasa el contenido del XML pero no se
preserva la identidad del nodo. Se puede especificar un mecanismo antes de una lista de
parámetros, como mecanismo por defecto para todos ellos, o después de cualquier parámetro,
para anular el comportamiento por defecto.
Para ilustrar la diferencia, si
x es un valor XML, estas dos consultas en un entorno
SQL:2006 producirían verdadero (true) y falso (false), respectivamente:
SELECT XMLQUERY('$a is $b' PASSING BY REF x AS a, x AS b NULL ON EMPTY);
SELECT XMLQUERY('$a is $b' PASSING BY VALUE x AS a, x AS b NULL ON EMPTY);
PostgreSQL aceptará
BY VALUE o BY REF en un constructor
XMLEXISTS o XMLTABLE, pero
los ignora. El tipo de datos xml almacena una representación
serializada en cadena de caracteres, por lo que no hay identidad de nodo que preservar, y
el paso siempre es efectivamente BY VALUE.
Las funciones basadas en XPath admiten el paso de un parámetro para que sirva como elemento de contexto de la expresión XPath, pero no admiten el paso de valores adicionales para que estén disponibles en la expresión como parámetros con nombre.
El tipo de datos xml de PostgreSQL
solo puede contener un valor en forma DOCUMENT
o CONTENT. El elemento de contexto de una expresión
XQuery/XPath debe ser un único nodo XML o valor atómico, pero XPath 1.0
lo restringe aún más para que sea solo un nodo XML, y no tiene ningún tipo de nodo
que permita CONTENT. El resultado es que un
DOCUMENT bien formado es la única forma de valor XML
que PostgreSQL puede suministrar como elemento de
contexto de XPath.