Sistema de tipos (XQuery)

XQuery es un lenguaje con establecimiento inflexible de tipos para tipos de esquema y un lenguaje con establecimiento flexible de tipos para datos sin tipo. Los tipos predefinidos de XQuery son los siguientes:

En este tema también se trata lo siguiente:

Tipos integrados de esquema XML

Los tipos integrados de esquema XML tienen el prefijo de espacio de nombres predefinido xs. Entre ellos, se encuentran xs:integer y xs:string. Todos estos tipos integrados son compatibles y se pueden utilizar al crear una colección de esquemas XML.

Al consultar XML con tipo, el tipo estático y dinámico de los nodos se determina a partir de la colección de esquemas XML asociada a la columna o variable que se consulta. Para obtener más información sobre los tipos estáticos y dinámicos, vea Contexto de expresiones y evaluación de consultas (XQuery). Por ejemplo, la consulta siguiente se especifica en una columna xml con tipo (Instructions). La expresión utiliza instance of para comprobar que el valor con tipo del atributo LotSize devuelto es de tipo xs:decimal.

SELECT Instructions.query('
   DECLARE namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
   data(/AWMI:root[1]/AWMI:Location[@LocationID=10][1]/@LotSize)[1] instance of xs:decimal
') AS Result
FROM Production.ProductModel
WHERE ProductModelID=7

Esta información de tipos la proporciona la colección de esquemas XML asociada a la columna. Para obtener más información, vea Representación de tipo de datos xml en la base de datos AdventureWorks.

Tipos definidos en el espacio de nombres de tipos de datos XPath

Los tipos definidos en el espacio de nombres http://www.w3.org/2004/07/xpath-datatypes tienen el prefijo predefinido xdt. La siguiente información se aplica a estos tipos:

  • Estos tipos no se pueden utilizar al crear una colección de esquemas XML. Estos tipos se utilizan en el sistema de tipos XQuery y se utilizan para tipos estáticos. Se puede realizar la conversión a los tipos atómicos, como xdt:untypedAtomic, en el espacio de nombres xdt.
  • Al consultar XML sin tipo, el tipo estático y dinámico de los nodos de elementos es xdt:untyped y el tipo de los valores de atributo es xdt:untypedAtomic. El resultado de un método query() genera XML sin tipo. Esto significa que los nodos XML se devuelven como xdt:untyped y xdt:untypedAtomic respectivamente.
  • No se admiten los tipos xdt:dayTimeDuration y xdt:yearMonthDuration.

En el ejemplo siguiente, la consulta se especifica con una variable XML sin tipo. La expresión, data(/a[1]), devuelve una secuencia de un valor atómico. La función data() devuelve el valor con tipo del elemento <a>. Dado que se consulta XML sin tipo, el tipo de valor devuelto es xdt:untypedAtomic. Por tanto, instance of devuelve True.

DECLARE @x xml
SET @x='<a>20</a>'
SELECT @x.query( 'data(/a[1]) instance of xdt:untypedAtomic' )

En lugar de recuperar el valor con tipo, la expresión (/a[1]) del ejemplo siguiente devuelve una secuencia de un elemento, el elemento <a>. La expresión instance of realiza la prueba de elementos para comprobar si el valor devuelto por la expresión es un nodo de elemento xdt:untyped type.

DECLARE @x xml
SET @x='<a>20</a>'
-- Is this an element node whose name is "a" and type is xdt:untyped.
SELECT @x.query( '/a[1] instance of element(a, xdt:untyped?)')
-- Is this an element node of type xdt:untyped.
SELECT @x.query( '/a[1] instance of element(*, xdt:untyped?)')
-- Is this an element node?
SELECT @x.query( '/a[1] instance of element()')

[!NOTA] Cuando se consulta una instancia XML con tipo y la expresión de la consulta incluye el eje principal, deja de estar disponible la información del tipo estático de los nodos resultantes. Sin embargo, el tipo dinámico sigue asociado a los nodos.

Valor con tipo y valor de cadena

Cada nodo tiene un valor con tipo y un valor de cadena. Para los datos XML con tipo, la colección de esquemas XML asociada a la columna o variable que se consulta proporciona el tipo del valor con tipo. Para los datos XML sin tipo, el tipo del valor con tipo es xdt:untypedAtomic.

Se puede utilizar la función data() o string() para recuperar el valor de un nodo:

En la siguiente colección de esquemas XML, se define el elemento <root> del tipo entero:

CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema">
      <element name="root" type="integer"/>
</schema>'
GO

En el ejemplo siguiente, la expresión primero recupera el valor con tipo de /root[1] y, después, le suma 3.

DECLARE @x xml(SC)
SET @x='<root>5</root>'
SELECT @x.query('data(/root[1]) + 3')

En el ejemplo siguiente, la expresión genera un error, porque string(/root[1]) en la expresión devuelve un valor de tipo cadena. A continuación, este valor se pasa a un operador aritmético que sólo utiliza como operandos valores de tipo numérico.

-- Fails because the argument is string type (must be numeric primitive type).
DECLARE @x xml(SC)
SET @x='<root>5</root>'
SELECT @x.query('string(/root[1]) + 3')

En el ejemplo siguiente se calcula el total de los atributos LaborHours. La función data() recupera los valores con tipo de los atributos LaborHours de todos los elementos <Location> para un modelo de producto. De acuerdo con el esquema XML asociado a la columna Instruction, LaborHours es de tipo xs:decimal.

SELECT Instructions.query(' 
DECLARE namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"; 
             sum(data(//AWMI:Location/@LaborHours)) 
') AS Result 
FROM Production.ProductModel 
WHERE ProductModelID=7

Esta consulta devuelve 12.75 como resultado.

[!NOTA] El uso explícito de la función data() en este ejemplo sólo tiene fines ilustrativos. Si no se especifica, sum() aplica de manera implícita la función data() para extraer los valores con tipo de los nodos.

Equiparación de tipos de secuencia

Un valor de expresión XQuery siempre es una secuencia de cero o más elementos. Un elemento puede ser un valor atómico o un nodo. El tipo de secuencia hace referencia a la capacidad de equiparar el tipo de secuencia devuelto por una expresión de consulta a un tipo específico. Por ejemplo:

  • Si el valor de la expresión es atómico, es posible que desee saber si es de tipo entero, decimal o cadena.
  • Si el valor de la expresión es un nodo XML, es posible que desee saber si es un nodo de comentarios, un nodo de instrucciones de procesamiento o un nodo de texto.
  • También puede saber si la expresión devuelve un elemento XML o un nodo de atributo con un nombre y tipo específicos.

Para conocer el tipo de secuencia correspondiente se puede utilizar el operador booleano instance of. Para obtener más información acerca de la expresión instance of, vea Expresiones SequenceType (XQuery).

Comparar el tipo de valor atómico devuelto por una expresión

Si una expresión devuelve una secuencia de valores atómicos, es posible que se deba buscar el tipo del valor en la secuencia. Los ejemplos siguientes muestran cómo se puede utilizar la sintaxis de tipo de secuencia para evaluar el tipo de valor atómico devuelto por una expresión.

Ejemplo A

El tipo de secuencia empty() se puede utilizar en una expresión de tipo de secuencia para determinar si la secuencia devuelta por la expresión especificada es una secuencia vacía.

En el ejemplo siguiente, el esquema XML permite que el elemento <root> tenga el atributo nillable:

CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema">
      <element name="root" nillable="true" type="byte"/>
</schema>'
GO

Ahora, si una instancia XML con tipo especifica un valor para el elemento <root>, instance of empty() devuelve False.

DECLARE @var XML(SC1)
SET @var = '<root>1</root>'
-- The following returns False
SELECT @var.query('data(/root[1]) instance of  empty() ')
GO

Si el elemento <root> tiene el atributo nillable en la instancia, su valor es una secuencia vacía e instance of empty() devuelve True.

DECLARE @var XML(SC)
SET @var = '<root xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />'
SELECT @var.query('data(/root[1]) instance of  empty() ')
GO

Ejemplo B

En ocasiones se desea evaluar el tipo de secuencia devuelto por una expresión antes de su procesamiento. Por ejemplo, puede haber un esquema XML en el que se defina un nodo como tipo de unión. En el ejemplo siguiente, el esquema XML de la colección define el atributo a como un tipo de unión cuyo valor puede ser de tipo decimal o de cadena.

-- Drop schema collection if it exists.
-- DROP XML SCHEMA COLLECTION SC.
-- GO
CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema">
  <element name="root">
    <complexType>
       <sequence/>
         <attribute name="a">
            <simpleType>
               <union memberTypes="decimal string"/>
            </simpleType>
         </attribute>
     </complexType>
  </element>
</schema>'
GO

Antes de procesar una instancia XML con tipo, se puede conocer el tipo del valor a del atributo. En el ejemplo siguiente, el valor a del atributo es un tipo decimal. Por tanto , instance of xs:decimal devuelve True.

DECLARE @var XML(SC)
SET @var = '<root a="2.5"/>'
SELECT @var.query('data((/root/@a)[1]) instance of xs:decimal')
GO

Ahora, cambie el valor a del atributo a un tipo de cadena. instance of xs:string devolverá True.

DECLARE @var XML(SC)
SET @var = '<root a="Hello"/>'
SELECT @var.query('data((/root/@a)[1]) instance of xs:string')
GO

Ejemplo C

Este ejemplo ilustra el efecto de la cardinalidad en una expresión de secuencia. El siguiente esquema XML define un elemento <root> de tipo byte que es nillable.

CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema">
      <element name="root" nillable="true" type="byte"/>
</schema>'
GO

En la consulta siguiente, dado que la expresión devuelve un singleton de tipo byte, instance of devuelve True.

DECLARE @var XML(SC)
SET @var = '<root>111</root>'
SELECT @var.query('data(/root[1]) instance of  xs:byte ') 
GO

Si se convierte el elemento <root> en nillable, el valor es una secuencia vacía. En otras palabras, la expresión, /root[1], devuelve una secuencia vacía. En consecuencia, instance of xs:byte devuelve False. Observe que, en este caso, la cardinalidad predeterminada es 1.

DECLARE @var XML(SC)
SET @var = '<root xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"></root>'
SELECT @var.query('data(/root[1]) instance of  xs:byte ') 
GO
-- result = false

Si se especifica la cardinalidad agregando el indicador de repetición (?), la expresión de secuencia devuelve True.

DECLARE @var XML(SC)
SET @var = '<root xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"></root>'
SELECT @var.query('data(/root[1]) instance of  xs:byte? ') 
GO
-- result = true

Tenga en cuenta que la comprobación en una expresión de tipo de secuencia se realiza en dos etapas:

  1. Primero, se determina si el tipo de la expresión coincide con el tipo especificado.
  2. En caso afirmativo, la comprobación determina si el número de elementos devueltos por la expresión coincide con el indicador de repetición especificado.

Si se dan ambas condiciones, la expresión instance of devuelve True.

Ejemplo D

En el ejemplo siguiente se especifica una consulta en una columna Instructions de tipo xml en la base de datos AdventureWorks: Es una columna XML con tipo, porque tiene un esquema asociado. Para obtener más información, vea Representación de tipo de datos xml en la base de datos AdventureWorks. El esquema XML define el atributo LocationID del tipo entero. Por tanto, en la expresión de secuencia, instance of xs:integer? devuelve True.

SELECT Instructions.query(' 
declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"; 
data(/AWMI:root[1]/AWMI:Location[1]/@LocationID) instance of xs:integer?') as Result 
FROM Production.ProductModel 
WHERE ProductModelID = 7

Comparar el tipo de nodo devuelto por una expresión

Si una expresión devuelve una secuencia de nodos, es posible que se deba determinar el tipo del nodo en la secuencia. Los ejemplos siguientes muestran cómo se puede utilizar la sintaxis de tipo de secuencia para evaluar el tipo de nodo devuelto por una expresión. Puede utilizar los siguientes tipos de secuencia:

  • item(): encuentra cualquier elemento coincidente en la secuencia.
  • node(): determina si la secuencia es un nodo.
  • processing-instruction(): determina si la expresión devuelve una instrucción de procesamiento.
  • comment(): determina si la expresión devuelve un comentario.
  • document-node(): determina si la expresión devuelve un nodo de documento.

Los ejemplos siguientes ilustran estos tipos de secuencia.

Ejemplo A

En este ejemplo, se ejecutan varias consultas en una variable XML sin tipo. Estas consultas ilustran el uso de tipos de secuencia.

DECLARE @var XML
SET @var = '<?xml-stylesheet href="someValue" type="text/xsl" ?>
<root>text node
  <!-- comment 1 --> 
  <a>Data a</a>
  <!-- comment  2 -->
</root>'

En la primera consulta, la expresión devuelve el valor con tipo del elemento <a>. En la segunda consulta, la expresión devuelve el elemento <a>. Ambos son elementos. Por tanto, ambas consultas devuelven True.

SELECT @var.query('data(/root[1]/a[1]) instance of item()')
SELECT @var.query('/root[1]/a[1] instance of item()')

Todas las expresiones XQuery de las tres consultas siguientes devuelven el elemento secundario del nodo de elemento <root>. Por tanto, la expresión de tipo de secuencia (instance of node()) devuelve True y las otras dos expresiones (instance of text() y instance of document-node()) devuelven False.

SELECT @var.query('(/root/*)[1] instance of node()')
SELECT @var.query('(/root/*)[1] instance of text()')
SELECT @var.query('(/root/*)[1] instance of document-node()') 

En la consulta siguiente, la expresión instance of document-node() devuelve True, porque el elemento primario del elemento <root> es un nodo de documento.

SELECT @var.query('(/root/..)[1] instance of document-node()') -- true

En la consulta siguiente, la expresión recupera el primer nodo de la instancia XML. Debido a que es un nodo de instrucciones de procesamiento, la expresión instance of processing-instruction() devuelve True.

SELECT @var.query('(/node())[1] instance of processing-instruction()')

Limitaciones de la implementación

Éstas son las limitaciones específicas:

  • No se admite document-node() con sintaxis de tipo de contenido.
  • No se admite la sintaxis processing-instruction(name).

Prueba de elementos

La prueba de elementos tiene como finalidad equiparar el nodo de elemento devuelto por una expresión a un nodo de elemento con un nombre y tipo específicos. Se pueden utilizar estas pruebas de elementos:

element ()
element(ElementName)
element(ElementName, ElementType?) 
element(*, ElementType?)

Prueba de atributos

La prueba de atributos determina si el atributo devuelto por una expresión es un nodo de atributo. Se pueden utilizar estas pruebas de atributos.

attribute()

attribute(AttributeName)

attribute(AttributeName, AttributeType)

Ejemplos de pruebas

Los ejemplos siguientes ilustran situaciones en las que son útiles las pruebas de elementos y atributos.

Ejemplo A

El siguiente esquema XML define el tipo complejo CustomerType, donde los elementos <firstName> y <lastName> son opcionales. Puede que sea necesario determinar, para una instancia XML específica, si existe un nombre para un cliente concreto.

CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="myNS" xmlns:ns="myNS">
  <complexType name="CustomerType">
     <sequence>
        <element name="firstName" type="string" minOccurs="0" 
                  nillable="true" />
        <element name="lastName" type="string" minOccurs="0"/>
     </sequence>
  </complexType>
  <element name="customer" type="ns:CustomerType"/>
</schema>
'
GO
DECLARE @var XML(SC)
SET @var = '<x:customer xmlns:x="myNS">
<firstName>SomeFirstName</firstName>
<lastName>SomeLastName</lastName>
</x:customer>'

La consulta siguiente utiliza una expresión instance of element (firstName) para determinar si el primer elemento secundario de <customer> es un elemento cuyo nombre es <firstName>. En este caso, devuelve True.

SELECT @var.query('declare namespace x="myNS"; 
     (/x:customer/*)[1] instance of element (firstName)')
GO

Si se quita el elemento <firstName> de la instancia, la consulta devolverá False.

También se puede utilizar lo siguiente:

  • La sintaxis de tipo de secuencia element(ElementName, ElementType?), como se muestra en la consulta siguiente. Busca un nodo de elemento nillable o no nillable coincidente cuyo nombre sea firstName y cuyo tipo sea xs:string.

    SELECT @var.query('declare namespace x="myNS"; 
    (/x:customer/*)[1] instance of element (firstName, xs:string?)')
    
  • La sintaxis de tipo de secuencia element(*, type?), como se muestra en la consulta siguiente. Busca un nodo de elemento coincidente cuyo tipo sea xs:string, sin importar su nombre.

    SELECT @var.query('declare namespace x="myNS"; (/x:customer/*)[1] instance of element (*, xs:string?)')
    GO
    

Ejemplo B

En el ejemplo siguiente se muestra cómo determinar si el nodo devuelto por una expresión es un nodo de elemento con un nombre específico. Se utiliza la prueba element().

En el ejemplo siguiente, los dos elementos <Customer> de la instancia XML que se consultan son de dos tipos diferentes (CustomerType y SpecialCustomerType). Se da por supuesto que se desea conocer el tipo del elemento <Customer> devuelto por la expresión. En la siguiente colección de esquemas XML se definen los tipos CustomerType y SpecialCustomerType.

CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema"
          targetNamespace="myNS"  xmlns:ns="myNS">
  <complexType name="CustomerType">
    <sequence>
      <element name="firstName" type="string"/>
      <element name="lastName" type="string"/>
    </sequence>
  </complexType>
  <complexType name="SpecialCustomerType">
     <complexContent>
       <extension base="ns:CustomerType">
        <sequence>
            <element name="Age" type="int"/>
        </sequence>
       </extension>
     </complexContent>
    </complexType>
   <element name="customer" type="ns:CustomerType"/>
</schema>
'
GO

Esta colección de esquemas XML se utiliza para crear una variable xml con tipo. La instancia XML asignada a esta variable tiene dos elementos <customer> de dos tipos diferentes. El primer elemento es de tipo CustomerType y el segundo elemento es de tipo SpecialCustomerType.

DECLARE @var XML(SC)
SET @var = '
<x:customer xmlns:x="myNS">
   <firstName>FirstName1</firstName>
   <lastName>LastName1</lastName>
</x:customer>
<x:customer xsi:type="x:SpecialCustomerType" xmlns:x="myNS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <firstName> FirstName2</firstName>
   <lastName> LastName2</lastName>
   <Age>21</Age>
</x:customer>'

En la consulta siguiente, la expresión instance of element (*, x:SpecialCustomerType ?) devuelve False, porque la expresión devuelve el primer elemento de cliente que no es de tipo SpecialCustomerType.

SELECT @var.query('declare namespace x="myNS"; 
    (/x:customer)[1] instance of element (*, x:SpecialCustomerType ?)')

Si se cambia la expresión de la consulta anterior y se recupera el segundo elemento <customer> (/x:customer)[2]), instance of devolverá True.

Ejemplo C

En este ejemplo se utiliza la prueba de atributos. El siguiente esquema XML define el tipo complejo CustomerType, con los atributos CustomerID y Age. El atributo Age es opcional. Quizás se desee determinar si el atributo Age está presente en el elemento <customer> para una instancia XML específica.

CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema"
       targetNamespace="myNS" xmlns:ns="myNS">
<complexType name="CustomerType">
  <sequence>
     <element name="firstName" type="string" minOccurs="0" 
               nillable="true" />
     <element name="lastName" type="string" minOccurs="0"/>
  </sequence>
  <attribute name="CustomerID" type="integer" use="required" />
  <attribute name="Age" type="integer" use="optional" />
 </complexType>
 <element name="customer" type="ns:CustomerType"/>
</schema>
'
GO

La consulta siguiente devuelve True porque hay un nodo de atributo cuyo nombre es Age en la instancia XML que se consulta. En esta expresión se utiliza la prueba de atributos attribute(Age). Como los atributos no están ordenados, la consulta utiliza la expresión FLWOR para recuperar todos los atributos y, después, comprobar cada atributo mediante la expresión instance of. En el ejemplo, primero se crea una colección de esquemas XML para crear una variable xml con tipo.

DECLARE @var XML(SC)
SET @var = '<x:customer xmlns:x="myNS" CustomerID="1" Age="22" >
<firstName>SomeFName</firstName>
<lastName>SomeLName</lastName>
</x:customer>'
SELECT @var.query('declare namespace x="myNS"; 
FOR $i in /x:customer/@*
RETURN
    IF ($i instance of attribute (Age)) THEN
        "true"
        ELSE
        ()')   
GO

Si se quita el atributo opcional Age de la instancia, la consulta anterior devuelve False.

En la prueba de atributos se puede especificar el nombre y tipo del atributo (attribute(name,type)).

SELECT @var.query('declare namespace x="myNS"; 
FOR $i in /x:customer/@*
RETURN
    IF ($i instance of attribute (Age, xs:integer)) THEN
        "true"
        ELSE
        ()')

Alternativamente, se puede especificar la sintaxis de tipo de secuencia attribute(*, type). De esta manera se buscará una coincidencia para el nodo de atributo, si el tipo de atributo coincide con el tipo especificado, sea cual sea su nombre.

Limitaciones de la implementación

Éstas son las limitaciones específicas:

  • En la prueba de elementos, el nombre del tipo debe ir seguido del indicador de repetición (?).
  • No se admite element(ElementName, TypeName).
  • No se admite element(*, TypeName).
  • No se admite schema-element().
  • No se admite schema-attribute(AttributeName).
  • No se admite la consulta explícita para xsi:type ni xsi:nil.

Vea también

Conceptos

Expresiones SequenceType (XQuery)
Conceptos básicos de XQuery

Otros recursos

Usar el Analizador de SQL Server

Ayuda e información

Obtener ayuda sobre SQL Server 2005