Utilisation du mode PATH

Comme l'explique la rubrique Construction de code XML à l'aide de FOR XML, le mode PATH permet de combiner des éléments et des attributs de façon simplifiée. En outre, il facilite l'extension de l'imbrication pour la représentation des propriétés complexes. Vous pouvez utiliser des requêtes en mode FOR XML EXPLICIT pour construire un document XML de ce type à partir d'un ensemble de lignes, mais le mode PATH offre une solution plus simple que les requêtes en mode EXPLICIT potentiellement lourdes. Le mode PATH, associé à la possibilité d'écrire des requêtes FOR XML imbriquées et à la directive TYPE de renvoi des instances de type xml, vous permet d'écrire des requêtes moins complexes.

En mode PATH, les noms ou alias de colonnes sont traités en tant qu'expressions XPath. Ces expressions indiquent comment les valeurs sont mappées au document XML. Chaque expression XPath est un chemin d'accès XPath relatif qui fournit le type d'élément, tel que les valeurs d'attribut, d'élément et scalaire, ainsi que le nom et la hiérarchie du nœud à générer par rapport à l'élément de ligne.

Cette rubrique décrit les conditions suivantes du mappage des colonnes d'un ensemble de lignes :

  • Colonnes sans nom
  • Colonnes avec nom
  • Colonnes avec un nom spécifié sous la forme d'un caractère générique (*)
  • Colonnes avec le nom d'un test de nœud XPath
  • Noms de colonnes avec le chemin d'accès spécifié sous la forme data()
  • Colonnes contenant une valeur NULL par défaut

Colonnes sans nom

Toute colonne sans nom est insérée. Par exemple, les colonnes calculées ou les requêtes scalaires imbriquées qui ne spécifient pas d'alias de colonne génèrent des colonnes sans nom. Si la colonne est de type xml, le contenu de cette instance de type de données est inséré. Sinon, le contenu de la colonne est inséré en tant que nœud de texte.

SELECT 2+2
FOR XML PATH

Génère ce document XML. Par défaut, pour chaque ligne de l'ensemble de lignes, un élément <row> est généré dans le document XML obtenu. Ce processus rappelle le mode RAW.

<row>4</row>

La requête suivante renvoie un ensemble de lignes de trois colonnes. La troisième colonne sans nom possède des données XML. Le mode PATH insère une instance du type xml.

SELECT ProductModelID,
       Name,
       Instructions.query('declare namespace MI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
                /MI:root/MI:Location 
              ') 
FROM Production.ProductModel
WHERE ProductModelID=7
FOR XML PATH 
go

Voici le résultat partiel :

<row>
  <ProductModelID>7</ProductModelID>
  <Name>HL Touring Frame</Name>
  <MI:Location ...LocationID="10" ...></MI:Location>
  <MI:Location ...LocationID="20" ...></MI:Location>
   ...
</row>

Colonnes avec nom

Les conditions suivantes sont celles dans lesquelles les colonnes de l'ensemble de lignes avec nom sont mappées, avec respect de la casse, au document XML obtenu :

  • Le nom de colonne commence par un arobase (@)
  • Le nom de colonne ne commence pas par un arobase (@)
  • Le nom de colonne ne commence pas par un arobase (@) et contient une barre oblique (/)
  • Plusieurs colonnes partagent le même préfixe.
  • Une colonne porte un nom différent.

Le nom de colonne commence par un arobase (@)

Si le nom de colonne commence par un arobase (@) et qu'il ne contient pas de barre oblique (/), un attribut de l'élément <row> possédant la valeur de colonne correspondante est créé. Par exemple, la requête suivante renvoie un ensemble de lignes de deux colonnes (@PmId, Name). Dans le document XML obtenu, un attribut PmId est ajouté à l'élément <row> correspondant et une valeur de ProductModelID lui est affectée.

SELECT ProductModelID as "@PmId",
       Name
FROM Production.ProductModel
WHERE ProductModelID=7
FOR XML PATH 
go

Voici le résultat obtenu :

<row PmId="7">
  <Name>HL Touring Frame</Name>
</row>

À un niveau donné, les attributs doivent précéder tous les autres types de nœuds, tels que les nœuds d'élément et les nœuds de texte. La requête suivante renvoie une erreur :

SELECT Name,
       ProductModelID as "@PmId"
FROM Production.ProductModel
WHERE ProductModelID=7
FOR XML PATH 
go

Le nom de colonne ne commence pas par un arobase (@)

Si le nom de colonne ne commence pas par un arobase (@), qu'il n'est pas l'un des tests de nœud XPath et qu'il ne contient pas de barre oblique (/), un élément XML sous-élément de l'élément de ligne, par défaut <row>, est créé.

La requête suivante spécifie le nom de colonne, qui est le résultat. Par conséquent, un élément enfant <result> est ajouté à l'élément <row>.

SELECT 2+2 as result
for xml PATH

Voici le résultat obtenu :

<row>
  <result>4</result>
</row>

La requête suivante spécifie le nom de colonne ManuWorkCenterInformation pour le document XML renvoyé par la requête XQuery portant sur la colonne Instructions de type xml. Par conséquent, un élément <ManuWorkCenterInformation> est ajouté en tant qu'enfant de l'élément <row>.

SELECT 
       ProductModelID,
       Name,
       Instructions.query('declare namespace MI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
                /MI:root/MI:Location 
              ') as ManuWorkCenterInformation
FROM Production.ProductModel
WHERE ProductModelID=7
FOR XML PATH 
go

Voici le résultat obtenu :

<row>
  <ProductModelID>7</ProductModelID>
  <Name>HL Touring Frame</Name>
  <ManuWorkCenterInformation>
    <MI:Location ...LocationID="10" ...></MI:Location>
    <MI:Location ...LocationID="20" ...></MI:Location>
     ...
  </ManuWorkCenterInformation>
</row>

Le nom de colonne ne commence pas par un arobase (@) et contient une barre oblique (/)

Si le nom de colonne ne commence pas par un arobase (@) mais qu'il contient une barre oblique (/), il indique une hiérarchie XML. Par exemple, si le nom de colonne est « Name1/Name2/Name3.../Namen », chaque partie Namei représente un nom d'élément imbriqué dans l'élément de ligne actuel (avec i égal à 1) ou situé sous l'élément nommé Namei-1. Si la partie Namen commence par « @ », elle est mappée à un attribut de Namen-1.

Par exemple, la requête suivante renvoie un ID et un nom d'employé représentés sous la forme d'un élément complexe EmpName qui contient un prénom (First), un deuxième prénom (Middle) et un nom de famille (Last).

SELECT EmployeeID "@EmpID", 
       FirstName  "EmpName/First", 
       MiddleName "EmpName/Middle", 
       LastName   "EmpName/Last"
FROM   HumanResources.Employee E, Person.Contact C
WHERE  E.EmployeeID = C.ContactID
AND    E.EmployeeID=1
FOR XML PATH

Les noms de colonnes sont utilisés comme chemin d'accès dans la construction du document XML en mode PATH. Le nom de colonne qui contient les valeurs d'ID d'employé commence par « @ ». Par conséquent, un attribut, EmpID, est ajouté à l'élément <row>. Le nom de toutes les autres colonnes contient une barre oblique (/) qui indique la hiérarchie. Le document XML obtenu possède l'enfant <EmpName> sous l'élément <row>, et l'enfant <EmpName> possède les éléments enfants <First>, <Middle> et <Last>.

<row EmpID="1">
  <EmpName>
    <First>Gustavo</First>
    <Last>Achong</Last>
  </EmpName>
</row>

Le deuxième prénom de l'employé est NULL et, par défaut, la valeur NULL correspond à l'absence de l'élément ou de l'attribut. Si vous souhaitez que des éléments soient générés pour les valeurs NULL, vous pouvez spécifier la directive ELEMENTS avec XSINIL, comme le montre la requête ci-après.

SELECT EmployeeID "@EmpID", 
       FirstName  "EmpName/First", 
       MiddleName "EmpName/Middle", 
       LastName   "EmpName/Last"
FROM   HumanResources.Employee E, Person.Contact C
WHERE  E.EmployeeID = C.ContactID
AND    E.EmployeeID=1
FOR XML PATH, ELEMENTS XSINIL

Voici le résultat obtenu :

<row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      EmpID="1">
  <EmpName>
    <First>Gustavo</First>
    <Middle xsi:nil="true" />
    <Last>Achong</Last>
  </EmpName>
</row>

Par défaut, le mode PATH génère des données XML centrées sur l'attribut. Par conséquent, la spécification de la directive ELEMENTS dans une requête en mode PATH est sans effet. Toutefois, comme le montre l'exemple précédent, la directive ELEMENTS, associée à XSINIL, permet de générer des éléments pour les valeurs NULL.

Outre l'ID et le nom, la requête suivante extrait l'adresse d'un employé. Conformément au chemin d'accès indiqué dans les noms des colonnes d'adresses, un élément enfant <Address> est ajouté à l'élément <row> et les détails de l'adresse sont ajoutés en tant qu'éléments enfants de l'élément <Address>.

SELECT EmployeeID   "@EmpID", 
       FirstName    "EmpName/First", 
       MiddleName   "EmpName/Middle", 
       LastName     "EmpName/Last",
       AddressLine1 "Address/AddrLine1",
       AddressLine2 "Address/AddrLIne2",
       City         "Address/City"
FROM   HumanResources.Employee E, Person.Contact C, Person.Address A
WHERE  E.EmployeeID = C.ContactID
AND    E.AddressID = A.AddressID
AND    E.EmployeeID=1
FOR XML PATH

Voici le résultat obtenu :

<row EmpID="1">
  <EmpName>
    <First>Gustavo</First>
    <Last>Achong</Last>
  </EmpName>
  <Address>
    <AddrLine1>7726 Driftwood Drive</AddrLine1>
    <City>Monroe</City>
  </Address>
</row>

Plusieurs colonnes partagent le même préfixe de chemin d'accès

Si plusieurs colonnes partagent le même préfixe de chemin d'accès, elles sont regroupées sous le même nom. Si différents préfixes d'espace de noms sont utilisés alors qu'ils sont liés au même espace de noms, un chemin d'accès est considéré comme différent. Dans la requête précédente, les colonnes FirstName, MiddleName et LastName partagent le même préfixe EmpName. Par conséquent, elles sont ajoutées en tant qu'enfants de l'élément <EmpName>. Cela était également le cas lors de la création de l'élément <Address> dans l'exemple précédent.

Une colonne porte un nom différent

Si une colonne intermédiaire et portant un nom différent apparaît, elle rompt le regroupement, comme le montre la requête modifiée suivante. La requête rompt le regroupement de FirstName, MiddleName et LastName, tel que spécifié dans la requête précédente, en ajoutant des colonnes d'adresse entre les colonnes FirstName et MiddleName.

SELECT EmployeeID "@EmpID", 
       FirstName "EmpName/First", 
       AddressLine1 "Address/AddrLine1",
       AddressLine2 "Address/AddrLIne2",
       City "Address/City",
       MiddleName "EmpName/Middle", 
       LastName "EmpName/Last"
FROM   HumanResources.EmployeeAddress E, Person.Contact C, Person.Address A
WHERE  E.EmployeeID = C.ContactID
AND    E.AddressID = A.AddressID
AND    E.EmployeeID=1
FOR XML PATH

Par conséquent, la requête crée deux éléments <EmpName>. Le premier élément <EmpName> possède l'élément enfant <FirstName> et le second élément <EmpName> possède les éléments enfants <MiddleName> et <LastName>.

Voici le résultat obtenu :

<row EmpID="1">
  <EmpName>
    <First>Gustavo</First>
  </EmpName>
  <Address>
    <AddrLine1>7726 Driftwood Drive</AddrLine1>
    <City>Monroe</City>
  </Address>
  <EmpName>
    <Last>Achong</Last>
  </EmpName>
</row>

Colonnes avec un nom spécifié sous la forme d'un caractère générique

Si le nom de colonne spécifié est un caractère générique (*), le contenu de la colonne concernée est inséré comme si aucun nom de colonne n'était spécifié. Si cette colonne est une colonne de type non-xml, le contenu de la colonne est inséré en tant que nœud de texte, comme le montre l'exemple suivant :

SELECT EmployeeID "@EmpID", 
       FirstName "*", 
       MiddleName "*", 
       LastName "*"
FROM   HumanResources.Employee E, Person.Contact C
WHERE  E.EmployeeID = C.ContactID
AND    E.EmployeeID=1
FOR XML PATH

Voici le résultat obtenu :

<row EmpID="1">GustavoAchong</row>

Si la colonne est de type xml, l'arborescence XML correspondante est insérée. Par exemple, la requête suivante spécifie « * » pour le nom de la colonne qui contient le document XML renvoyé par la requête XQuery portant sur la colonne Instructions.

SELECT 
       ProductModelID,
       Name,
       Instructions.query('declare namespace MI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"
                /MI:root/MI:Location 
              ') as "*"
FROM Production.ProductModel
WHERE ProductModelID=7
FOR XML PATH 
go

Voici le résultat obtenu : le document XML renvoyé par la requête XQuery est inséré sans élément d'habillage.

<row>
  <ProductModelID>7</ProductModelID>
  <Name>HL Touring Frame</Name>
  <MI:Location LocationID="10">...</MI:Location>
  <MI:Location LocationID="20">...</MI:Location>
...
</row>

Colonnes avec le nom d'un test de nœud XPath

Si le nom de colonne est l'un des tests de nœud XPath, le contenu est mappé comme le montre le tableau ci-après.

Lorsque le nom de colonne est un test de nœud XPath, le contenu est mappé au nœud correspondant. Si le type SQL de la colonne est xml, une erreur est renvoyée.

Nom de colonne Comportement

text()

Dans le cas d'une colonne nommée text(), la valeur de chaîne contenue dans cette colonne est ajoutée en tant que nœud de texte.

comment()

Dans le cas d'une colonne nommée comment(), la valeur de chaîne contenue dans cette colonne est ajoutée en tant que commentaire XML.

node()

Dans le cas d'une colonne nommée node(), le résultat est le même que lorsque le nom de colonne est un caractère générique (*).

processing-instruction(name)

Dans le cas d'une colonne dont le nom est une instruction de traitement, la valeur de chaîne contenue dans cette colonne est ajoutée en tant que valeur PI du nom cible de l'instruction de traitement.

Noms de colonnes avec le chemin d'accès spécifié sous la forme data()

Si le chemin d'accès spécifié comme nom de colonne est « data() », la valeur est traitée en tant que valeur atomique dans le document XML généré. Un espace est ajouté au document XML si l'élément suivant dans la sérialisation est également une valeur atomique. Cela est utile lorsque vous créez une liste de valeurs d'élément et d'attribut de type liste. La requête suivante extrait l'ID de modèle, le nom et la liste des produits pour le modèle concerné.

SELECT ProductModelID       as "@ProductModelID",
       Name                 as "@ProductModelName",
      (SELECT ProductID as "data()"
       FROM   Production.Product
       WHERE  Production.Product.ProductModelID = 
              Production.ProductModel.ProductModelID
      FOR XML PATH (''))    as "@ProductIDs"
FROM  Production.ProductModel
WHERE ProductModelID= 7 
FOR XML PATH('ProductModelData')

L'instruction SELECT imbriquée extrait une liste d'ID de produit. Elle spécifie « data() » comme nom de colonne pour les ID de produit. Étant donné que le mode PATH spécifie une chaîne vide pour le nom d'élément de ligne, aucun élément de ligne n'est généré. À la place, les valeurs sont renvoyées comme étant affectées à un attribut ProductIDs de l'élément de ligne <ProductModelData> de l'instruction SELECT parente. Voici le résultat obtenu :

<ProductModelData ProductModelID="7" 
                  ProductModelName="HL Touring Frame" 
                  ProductIDs="885 887 888 889 890 891 892 893" />

Colonnes contenant une valeur NULL par défaut

Par défaut, une valeur NULL dans une colonne correspond à l'absence de l'attribut, du nœud ou de l'élément. Vous pouvez remplacer ce comportement par défaut en demandant un document XML centré sur l'élément à l'aide de la directive ELEMENTS et en spécifiant XSINIL afin de demander l'ajout d'éléments pour les valeurs NULL, comme le montre la requête suivante :

SELECT EmployeeID as "@EmpID", 
       FirstName  as "EmpName/First", 
       MiddleName as "EmpName/Middle", 
       LastName   as "EmpName/Last"
FROM   HumanResources.Employee E, Person.Contact C
WHERE  E.EmployeeID = C.ContactID
AND    E.EmployeeID=1
FOR XML PATH, ELEMENTS XSINIL

Le résultat est le suivant. Si XSINIL n'est pas spécifié, l'élément <Middle> est absent.

<row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" EmpID="1">
  <EmpName>
    <First>Gustavo</First>
    <Middle xsi:nil="true" />
    <Last>Achong</Last>
  </EmpName>
</row>

Prise en charge des espaces de noms

Cette version prend en charge les espaces de noms en mode PATH à l'aide de WITH NAMESPACES. Par exemple, la requête ci-après montre comment recourir à la syntaxe WITH NAMESPACES pour déclarer un espace de noms (« a: ») en vue de son utilisation dans l'instruction SELECT suivante :

WITH XMLNAMESPACES('a' as a)
SELECT 1 as 'a:b'
FOR XML PATH

Exemples

Ces exemples montrent comment utiliser le mode PATH pour générer un document XML à partir d'une requête SELECT. Nombre de ces requêtes sont spécifiées par rapport aux documents XML des instructions de fabrication de bicyclettes stockés dans la colonne Instructions de la table ProductModel. Pour plus d'informations sur les instructions XML, consultez Représentation du type de données xml dans la base de données AdventureWorks.

A. Spécification d'une requête simple en mode PATH

Cette requête spécifie un mode FOR XML PATH.

SELECT 
       ProductModelID,
       Name
FROM Production.ProductModel
WHERE ProductModelID=122 or ProductModelID=119
FOR XML PATH
go

Le résultat suivant est un document XML centré sur l'élément dans lequel chaque valeur de colonne de l'ensemble de lignes obtenu est inclus dans un élément. Étant donné que la clause SELECT ne spécifie aucun alias pour les noms de colonnes, les noms d'éléments enfants générés sont les mêmes que les noms de colonnes correspondants dans la clause SELECT. Pour chaque ligne de l'ensemble de lignes, une balise <row> est ajoutée.

<row>
  <ProductModelID>122</ProductModelID>
  <Name>All-Purpose Bike Stand</Name>
</row>
<row>
  <ProductModelID>119</ProductModelID>
  <Name>Bike Wash</Name>
</row>

Le résultat suivant est le même que la requête en mode RAW avec l'option ELEMENTS spécifiée. Il renvoie un document XML centré sur l'élément avec un élément <row> par défaut pour chaque ligne de l'ensemble de résultats.

SELECT ProductModelID,
       Name
FROM Production.ProductModel
WHERE ProductModelID=122 or ProductModelID=119
FOR XML RAW, ELEMENTS

Vous pouvez éventuellement spécifier le nom d'élément de ligne pour remplacer l'élément <row> par défaut. Par exemple, la requête suivante renvoie l'élément <ProductModel> de chaque ligne de l'ensemble de lignes.

SELECT ProductModelID,
       Name
FROM Production.ProductModel
WHERE ProductModelID=122 or ProductModelID=119
FOR XML PATH ('ProductModel')
Go

Le document XML obtenu possède un nom d'élément de ligne spécifié.

<ProductModel>
  <ProductModelID>122</ProductModelID>
  <Name>All-Purpose Bike Stand</Name>
</ProductModel>
<ProductModel>
  <ProductModelID>119</ProductModelID>
  <Name>Bike Wash</Name>
</ProductModel>

Si vous spécifiez une chaîne nulle, l'élément d'habillage n'est pas généré.

SELECT ProductModelID,
       Name
FROM Production.ProductModel
WHERE ProductModelID=122 or ProductModelID=119
FOR XML PATH ('')
Go

Voici le résultat obtenu :

<ProductModelID>122</ProductModelID>
<Name>All-Purpose Bike Stand</Name>
<ProductModelID>119</ProductModelID>
<Name>Bike Wash</Name>

B. Spécification de noms de colonnes de type XPath

Dans la requête suivante, le nom de colonne ProductModelID spécifié commence par « @ » et ne contient pas de barre oblique (/). Par conséquent, un attribut de l'élément <row> ayant la valeur de colonne correspondante est créé dans le document XML obtenu.

SELECT ProductModelID as "@id",
       Name
FROM Production.ProductModel
WHERE ProductModelID=122 or ProductModelID=119
FOR XML PATH ('ProductModelData')
go

Voici le résultat obtenu :

< ProductModelData id="122">
    <Name>All-Purpose Bike Stand</Name>
</ ProductModelData >
< ProductModelData id="119">
    <Name>Bike Wash</Name>
</ ProductModelData >

Vous pouvez ajouter un élément de niveau supérieur unique en spécifiant l'option root dans FOR XML.

SELECT ProductModelID as "@id",
       Name
FROM Production.ProductModel
WHERE ProductModelID=122 or ProductModelID=119
FOR XML PATH ('ProductModelData'), root ('Root')
go

Pour générer une hiérarchie, vous pouvez inclure une syntaxe de type PATH. Par exemple, remplacez le nom de la colonne Name par « SomeChild/ModelName » afin d'obtenir un document XML avec hiérarchie, comme le montre le résultat suivant :

<Root>
  <ProductModelData id="122">
    <SomeChild>
      <ModelName>All-Purpose Bike Stand</ModelName>
    </SomeChild>
  </ProductModelData>
  <ProductModelData id="119">
    <SomeChild>
      <ModelName>Bike Wash</ModelName>
    </SomeChild>
  </ProductModelData>
</Root>

Outre l'ID et le nom du modèle de produit, la requête suivante extrait les emplacements des instructions de fabrication du modèle. Étant donné que la colonne Instructions est de type xml, la méthode query() de type de données xml est spécifiée pour extraire l'emplacement.

SELECT ProductModelID as "@id",
       Name,
       Instructions.query('declare namespace MI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
                /MI:root/MI:Location 
              ') as ManuInstr
FROM Production.ProductModel
WHERE ProductModelID=7
FOR XML PATH ('ProductModelData'), root ('Root')
go

Le résultat partiel est le suivant. Étant donné que la requête spécifie ManuInstr comme nom de colonne, le document XML renvoyé par la méthode query() est inclus dans une balise <ManuInstr>, comme le montre la syntaxe suivante :

<Root>
  <ProductModelData id="7">
    <Name>HL Touring Frame</Name>
    <ManuInstr>
      <MI:Location xmlns:MI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions" 
        <MI:step>...</MI:step>...
      </MI:Location>
      ...
    </ManuInstr>
  </ProductModelData>
</Root>

Dans la requête FOR XML précédente, vous pouvez inclure des espaces de noms pour les éléments <Root> et <ProductModelData>. Pour ce faire, vous pouvez définir la liaison préfixe/espace de noms à l'aide de WITH XMLNAMESPACES puis utiliser des préfixes dans la requête FOR XML. Pour plus d'informations, consultez Ajout d'espaces de noms à l'aide de WITH XMLNAMESPACES.

WITH XMLNAMESPACES (
   'uri1' as ns1,  
   'uri2' as ns2,
   'https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions' as MI)
SELECT ProductModelID as "ns1:ProductModelID",
       Name           as "ns1:Name",
       Instructions.query('
                /MI:root/MI:Location 
              ') 
FROM Production.ProductModel
WHERE ProductModelID=7
FOR XML PATH ('ns2:ProductInfo'), root('ns1:root')
go

Le préfixe MI est également défini dans WITH XMLNAMESPACES. Par conséquent, la méthode query() du type xml spécifié ne définit pas le préfixe dans le prologue de la requête. Voici le résultat obtenu :

<ns1:root xmlns:MI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions" xmlns="uri2" xmlns:ns2="uri2" xmlns:ns1="uri1">
  <ns2:ProductInfo>
    <ns1:ProductModelID>7</ns1:ProductModelID>
    <ns1:Name>HL Touring Frame</ns1:Name>
    <MI:Location xmlns:MI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions" 
       LaborHours="2.5" LotSize="100" MachineHours="3" SetupHours="0.5" LocationID="10" >
       <MI:step>
          Insert <MI:material>aluminum sheet MS-2341</MI:material> into the <MI:tool>T-85A framing tool</MI:tool>. 
       </MI:step>
         ...
    </MI:Location>
     ...
  </ns2:ProductInfo>
</ns1:root>

C. Génération d'une liste de valeurs à l'aide du mode PATH

Pour chaque modèle de produit, cette requête construit une liste de valeurs d'ID de produit. Pour chaque ID de produit, la requête construit également des éléments imbriqués <ProductName>, comme le montre le fragment XML suivant :

<ProductModelData ProductModelID="7" ProductModelName="..."  
                  ProductIDs="product id list in the product model" >
  <ProductName>...</ProductName>
  <ProductName>...</ProductName>
  ...
</ProductModelData>

La requête ci-après génère le document XML souhaité :

SELECT ProductModelID     as "@ProductModelID",
       Name               as "@ProductModelName",
      (SELECT ProductID as "data()"
       FROM   Production.Product
       WHERE  Production.Product.ProductModelID = 
              Production.ProductModel.ProductModelID
       FOR XML PATH ('')) as "@ProductIDs",
       (SELECT Name as "ProductName"
       FROM   Production.Product
       WHERE  Production.Product.ProductModelID = 
              Production.ProductModel.ProductModelID
        FOR XML PATH ('')) as "ProductNames"
FROM   Production.ProductModel
WHERE  ProductModelID= 7 or ProductModelID=9
FOR XML PATH('ProductModelData')

Notez les points suivants par rapport à la requête ci-dessus :

  • La première clause SELECT imbriquée renvoie une liste d'identificateurs ProductID en utilisant data() comme nom de colonne. Étant donné que la requête spécifie une chaîne vide comme nom d'élément de ligne dans FOR XML PATH, aucun élément n'est généré. À la place, la liste de valeurs est affectée à l'attribut ProductID.
  • La seconde clause SELECT imbriquée extrait les noms des produits du modèle concerné. Elle génère des éléments <ProductName> qui sont renvoyés inclus dans l'élément <ProductNames>, car la requête spécifie ProductNames comme nom de colonne.

Voici le résultat partiel :

<ProductModelData PId="7" 
                  ProductModelName="HL Touring Frame" 
                  ProductIDs="885 887 ...">
  <ProductNames>
    &lt;ProductName&gt;HL Touring Frame - Yellow, 60&lt;/ProductName&gt;
    &lt;ProductName&gt;HL Touring Frame - Yellow, 46&lt;/ProductName&gt;</ProductNames>
    ...
</ProductModelData>
<ProductModelData PId="9" 
                  ProductModelName="LL Road Frame" 
                  ProductIDs="722 723 724 ...">
  <ProductNames>
     &lt;ProductName&gt;LL Road Frame - Black, 58&lt;/ProductName&gt;
     &lt;ProductName&gt;LL Road Frame - Black, 60&lt;/ProductName&gt;
     &lt;ProductName&gt;LL Road Frame - Black, 62&lt;/ProductName&gt;
     ...
  </ProductNames>
</ProductModelData>

La sous-requête qui construit les noms de produits renvoie le résultat sous la forme d'une chaîne décomposée en entités puis ajoutée au document XML. Si vous ajoutez la directive type, FOR XML PATH (''), type, la sous-requête renvoie le résultat en tant que type xml et aucune décomposition en entités ne se produit.

SELECT ProductModelID as "@ProductModelID",
      Name as "@ProductModelName",
      (SELECT ProductID as "data()"
       FROM   Production.Product
       WHERE  Production.Product.ProductModelID = 
              Production.ProductModel.ProductModelID
       FOR XML PATH ('')
       ) as "@ProductIDs",
       (
       SELECT Name as "ProductName"
       FROM   Production.Product
       WHERE  Production.Product.ProductModelID = 
              Production.ProductModel.ProductModelID
       FOR XML PATH (''), type
       ) as "ProductNames"
       
FROM Production.ProductModel
WHERE ProductModelID= 7 or ProductModelID=9
FOR XML PATH('ProductModelData')

D. Ajout d'espaces de noms au document XML obtenu

Comme l'explique la rubrique Ajout d'espaces de noms à l'aide de WITH XMLNAMESPACES, vous pouvez utiliser WITH XMLNAMESPACES pour inclure des espaces de noms dans les requêtes en mode PATH. Par exemple, les noms spécifiés dans la clause SELECT comprennent des préfixes d'espace de noms. La requête en mode PATH suivante construit un document XML avec des espaces de noms.

SELECT 'en'    as "English/@xml:lang",
       'food'  as "English",
       'ger'   as "German/@xml:lang",
       'Essen' as "German"
FOR XML PATH ('Translation')
go

L'attribut @xml:lang ajouté à l'élément <English> est défini dans l'espace de noms xml prédéfini.

Voici le résultat obtenu :

<Translation>
  <English xml:lang="en">food</English>
  <German xml:lang="ger">Essen</German>
</Translation>

La requête suivante est similaire à l'exemple C, sauf qu'elle utilise WITH XMLNAMESPACES pour inclure des espaces de noms dans le résultat XML. Pour plus d'informations, consultez Ajout d'espaces de noms à l'aide de WITH XMLNAMESPACES.

WITH XMLNAMESPACES ('uri1' as ns1,  DEFAULT 'uri2')
SELECT ProductModelID as "@ns1:ProductModelID",
      Name as "@ns1:ProductModelName",
      (SELECT ProductID as "data()"
       FROM   Production.Product
       WHERE  Production.Product.ProductModelID = 
              Production.ProductModel.ProductModelID
       FOR XML PATH ('')
       ) as "@ns1:ProductIDs",
       (
       SELECT ProductID as "@ns1:ProductID", 
              Name as "@ns1:ProductName"
       FROM   Production.Product
       WHERE  Production.Product.ProductModelID = 
              Production.ProductModel.ProductModelID
       FOR XML PATH , type 
       ) as "ns1:ProductNames"
       
FROM Production.ProductModel
WHERE ProductModelID= 7 or ProductModelID=9
FOR XML PATH('ProductModelData'), root('root')

Voici le résultat obtenu :

<root xmlns="uri2" xmlns:ns1="uri1">
  <ProductModelData ns1:ProductModelID="7" ns1:ProductModelName="HL Touring Frame" ns1:ProductIDs="885 887 888 889 890 891 892 893">
    <ns1:ProductNames>
      <row xmlns="uri2" xmlns:ns1="uri1" ns1:ProductID="885" ns1:ProductName="HL Touring Frame - Yellow, 60" />
      <row xmlns="uri2" xmlns:ns1="uri1" ns1:ProductID="887" ns1:ProductName="HL Touring Frame - Yellow, 46" />
       ...
    </ns1:ProductNames>
  </ProductModelData>
  <ProductModelData ns1:ProductModelID="9" ns1:ProductModelName="LL Road Frame" ns1:ProductIDs="722 723 724 725 726 727 728 729 730 736 737 738">
    <ns1:ProductNames>
      <row xmlns="uri2" xmlns:ns1="uri1" ns1:ProductID="722" ns1:ProductName="LL Road Frame - Black, 58" />
        ...
    </ns1:ProductNames>
  </ProductModelData>
</root>

Voir aussi

Référence

Construction de code XML à l'aide de FOR XML

Concepts

Ajout d'espaces de noms à l'aide de WITH XMLNAMESPACES

Autres ressources

SELECT (Transact-SQL)

Aide et Informations

Assistance sur SQL Server 2005