Hinzufügen von Namespaces mithilfe von WITH XMLNAMESPACES

WITH XMLNAMESPACES (Transact-SQL) bietet folgende Namespace-URI-Unterstützung:

Verwenden von WITH XMLNAMESPACES in FOR XML-Abfragen

Mit WITH XMLNAMESPACES können Sie XML-Namespaces in FOR XML-Abfragen einbeziehen. Nehmen Sie beispielsweise folgende FOR XML-Abfrage:

SELECT ProductID, Name, Color
FROM   Production.Product
WHERE  ProductID=316 or ProductID=317
FOR XML RAW

Dies ist das Ergebnis:

<row ProductID="316" Name="Blade" />
<row ProductID="317" Name="LL Crankarm" Color="Black" />

Um Namespaces zu dem durch die FOR XML-Abfrage erstellten XML hinzuzufügen, legen Sie zuerst mit der WITH NAMESPACES-Klausel die Zuordnungen der Namespacepräfixe zu URIs fest. Verwenden Sie anschließend in der folgenden geänderten Abfrage die Namespacepräfixe, um die in der Abfrage verwendeten Namen festzulegen. Die WITH XMLNAMESPACES-Klausel legt die Zuordnung des Namespacepräfixes (ns1) zum URI (uri) fest. Das ns1-Präfix wird dann beim Festlegen der Element- und Attributnamen verwendet, die durch die FOR XML-Abfrage erstellt werden sollen.

WITH XMLNAMESPACES ('uri' as ns1)
SELECT ProductID as 'ns1:ProductID',
       Name      as 'ns1:Name', 
       Color     as 'ns1:Color'
FROM Production.Product
WHERE ProductID=316 or ProductID=317
FOR XML RAW ('ns1:Prod'), ELEMENTS

Das XML-Ergebnis enthält die Namespacepräfixe:

<ns1:Prod xmlns:ns1="uri">
  <ns1:ProductID>316</ns1:ProductID>
  <ns1:Name>Blade</ns1:Name>
</ns1:Prod>
<ns1:Prod xmlns:ns1="uri">
  <ns1:ProductID>317</ns1:ProductID>
  <ns1:Name>LL Crankarm</ns1:Name>
  <ns1:Color>Black</ns1:Color>
</ns1:Prod>

Für die WITH XMLNAMESPACES-Klausel gilt Folgendes:

  • Sie wird nur im RAW-, AUTO- und PATH-Modus der FOR XML-Abfragen unterstützt. Der EXPLICIT-Modus wird nicht unterstützt.

  • Sie wirkt sich nur auf die Namespacepräfixe von FOR XML-Abfragen und auf die xml-Datentypmethode aus – aber nicht auf den XML-Parser. Die folgende Abfrage gibt beispielsweise einen Fehler zurück, weil das XML-Dokument keine Namespacedeklaration für das myNS-Präfix enthält.

  • Die FOR XML-Direktiven XMLSCHEMA und XMLDATA können nicht zusammen mit der WITH XMLNAMESPACES-Klausel verwendet werden.

    CREATE TABLE T (x xml)
    go
    WITH XMLNAMESPACES ('http://abc' as myNS )
    INSERT INTO T VALUES('<myNS:root/>')
    

Verwenden der XSINIL-Direktive

Wenn Sie die ELEMENTS XSINIL-Direktive verwenden, können Sie das xsi-Präfix nicht in der WITH XMLNAMESPACES-Klausel definieren. Es wird stattdessen automatisch hinzugefügt, wenn Sie ELEMENTS XSINIL verwenden. Die folgende Abfrage verwendet ELEMENTS XSINIL, die elementzentriertes XML generiert, wo Elementen, deren xsi:nil-Attribut auf True festgelegt ist, Nullwerte zugeordnet werden.

WITH XMLNAMESPACES ('uri' as ns1)
SELECT ProductID as 'ns1:ProductID',
       Name      as 'ns1:Name', 
       Color     as 'ns1:Color'
FROM Production.Product
WHERE ProductID=316 
FOR XML RAW, ELEMENTS XSINIL

Dies ist das Ergebnis:

<row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns1="uri">
  <ns1:ProductID>316</ns1:ProductID>
  <ns1:Name>Blade</ns1:Name>
  <ns1:Color xsi:nil="true" />
</row>

Angeben von Standardnamespaces

Statt ein Namespacepräfix zu deklarieren, können Sie mit dem DEFAULT-Schlüsselwort einen Standardnamespace deklarieren. In der FOR XML-Abfrage wird der Standardnamespace mit den XML-Knoten des resultierenden XML verbunden. Im folgenden Beispiel definiert WITH XMLNAMESPACES zwei Namespacepräfixe, die gemeinsam über einen Standardnamespace definiert sind.

WITH XMLNAMESPACES ('uri1' as ns1, 
                    'uri2' as ns2,
                    DEFAULT 'uri2')
SELECT ProductID, 
      Name,
      Color
FROM Production.Product 
WHERE ProductID=316 or ProductID=317
FOR XML RAW ('ns1:Product'), ROOT('ns2:root'), ELEMENTS

Die FOR XML-Abfrage generiert elementzentriertes XML. Die Abfrage verwendet bei der Knotenbenennung beide Namespacepräfixe. In der SELECT-Klausel legen ProductID, Name und Color keine Namen mit einem Präfix fest. Daher gehören die entsprechenden Elemente des resultierenden XML zum Standardnamespace.

<ns2:root xmlns="uri2" xmlns:ns2="uri2" xmlns:ns1="uri1">
  <ns1:Product>
    <ProductID>316</ProductID>
    <Name>Blade</Name>
  </ns1:Product>
  <ns1:Product>
    <ProductID>317</ProductID>
    <Name>LL Crankarm</Name>
    <Color>Black</Color>
  </ns1:Product>
</ns2:root>

Die folgende Abfrage ähnelt der vorherigen, allerdings ist der FOR XML AUTO-Modus festgelegt.

WITH XMLNAMESPACES ('uri1' as ns1,  'uri2' as ns2,DEFAULT 'uri2')
SELECT ProductID, 
      Name,
      Color
FROM Production.Product as "ns1:Product"
WHERE ProductID=316 or ProductID=317
FOR XML AUTO, ROOT('ns2:root'), ELEMENTS

Verwenden vordefinierter Namespaces

Wenn Sie vordefinierte Namespaces verwenden, müssen Sie (mit Ausnahme von xml-Namespace und xsi-Namespace, wenn ELEMENTS XSINIL verwendet wird) die Namespacebindung mit WITH XMLNAMESPACES explizit festlegen. Die folgende Abfrage definiert explizit den Namespacepräfix für die URI-Bindung für den vordefinierten Namespace (urn:schemas-microsoft-com:xml-sql).

WITH XMLNAMESPACES ('urn:schemas-microsoft-com:xml-sql' as sql)
SELECT 'SELECT * FROM Customers FOR XML AUTO, ROOT("a")' AS "sql:query"
FOR XML PATH('sql:root')

Dies ist das Ergebnis. SQLXML-Benutzer kennen diese XML-Vorlage. Weitere Informationen finden Sie unter SQLXML 4.0-Programmierkonzepte.

<sql:root xmlns:sql="urn:schemas-microsoft-com:xml-sql">
  <sql:query>SELECT * FROM Customers FOR XML AUTO, ROOT("a")</sql:query>
</sql:root>

Nur das xml-Namespacepräfix kann verwendet werden ohne explizit in WITH XMLNAMESPACES definiert zu sein, was die folgende Abfrage im PATH-Modus zeigt. Wenn das Präfix deklariert wird, muss es außerdem mit dem Namespace http://www.w3.org/XML/1998/namespace verbunden werden. Die in der SELECT-Klausel festgelegten Namen verweisen auf das xml-Namespacepräfix, das nicht explizit mit WITH XMLNAMESPACES definiert ist.

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

Die @xml:lang-Attribute verwenden den vordefinierten xml-Namespace. Da in XML Version 1.0 keine explizite Deklaration der xml-Namespacebindung notwendig ist, enthält das Ergebnis keine explizite Deklaration der Namespacebindung.

Dies ist das Ergebnis:

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

Verwenden von WITH XMLNAMESPACES mit den xml-Datentypmethoden

Alle in einer SELECT-Abfrage oder in UPDATE (bei der modify()-Methode) festgelegten xml-Datentypmethoden müssen die Namespacedeklaration in ihrem Prolog wiederholen. Dies kann einige Zeit in Anspruch nehmen. Die folgende Abfrage ruft beispielsweise Produktmodell-IDs ab, deren Katalogbeschreibungen eine Spezifikation enthalten. Dies geschieht, wenn das Element <Specifications> vorhanden ist.

SELECT ProductModelID, CatalogDescription.query('
declare namespace pd="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
    <Product 
        ProductModelID= "{ sql:column("ProductModelID") }" 
        />
') AS Result
FROM Production.ProductModel
WHERE CatalogDescription.exist('
    declare namespace  pd="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
     /pd:ProductDescription[(pd:Specifications)]'
    ) = 1

In der vorherigen Abfrage deklarieren die query()- und die exist()-Methode in ihrem Prolog denselben Namespace. Beispiel:

 declare namespace pd="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";

Alternativ können Sie zuerst WITH XMLNAMESPACES deklarieren und in der Abfrage dann die Namespacepräfixe verwenden. In diesem Fall enthalten die query()- und die exist()-Methode im Prolog keine Namespacedeklaration.

WITH XMLNAMESPACES ('https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription' as pd)
SELECT ProductModelID, CatalogDescription.query('
    <Product 
        ProductModelID= "{ sql:column("ProductModelID") }" 
        />
') AS Result
FROM Production.ProductModel
WHERE CatalogDescription.exist('
     /pd:ProductDescription[(pd:Specifications)]'
    ) = 1
Go

Eine explizite Deklaration im XQuery-Prolog überschreibt das in der WITH-Klausel definierte Namespacepräfix und den Standardelementnamespace.