共用方式為


使用 EXPLICIT 模式

如<使用 FOR XML 建構 XML>主題中所述,RAW 和 AUTO 模式對從查詢結果產生之 XML 形式的控制不大。但是,EXPLICIT 模式在由查詢結果產生想要的 XML 方面,可提供的彈性最大。

EXPLICIT 模式詢必須以特定方式寫入,如此一來有關所需 XML 的額外資訊 (例如 XML 中將會構成的巢狀結構 ),就可以明確指定在查詢內。根據您要求使用的 XML,撰寫 EXPLICIT 模式查詢會相當繁雜。您可能會發現對撰寫 EXPLICIT 模式查詢而言,使用 PATH 模式搭配巢狀結構是較為簡單的替代方法。

因為您會將想要的 XML 描述為 EXPLICIT 模式中查詢的一部份,所以您必須確定產生的 XML 有效而且格式正確。

EXPLICIT 模式中的資料列集處理

EXPLICIT 模式會將執行查詢所產生的資料列集轉換為 XML 文件。資料列集必須具有特定格式,EXPLICIT 模式才能產生 XML 文件。您必須撰寫 SELECT 查詢,以特定格式產生資料列集 (通用資料表),如此處理邏輯之後才能產生您想要的 XML。

首先,查詢必須產生以下兩個中繼資料資料行:

  • 第一個資料行必須提供目前元素的標記編號、整數類型,而且該資料行名稱必須為**「標記」**。您的查詢必須要為資料列集將要建構的每個元素,提供唯一的標記編號。
  • 第二個資料行必須提供父元素的標記編號,而且此資料行名稱必須為**「父系」**。如此一來,「標記」與「父系」資料行就可以提供階層資訊。

這些中繼資料資料行值連同資料行名稱中的資訊,都會用來產生您想要的 XML。請注意,您的查詢必須以特定的方式提供資料行名稱。此外,也請注意,**「父系」**資料行中的 0 或 NULL 代表該對應元素沒有父系。該元素會作為最上層元素增加到 XML。

若要瞭解查詢產生的通用資料表是如何處理以產生 XML 結果,假設您已經撰寫可以處理此通用資料表的查詢:

範例通用資料表

記下有關此通用資料表的下列各項:

  • 前兩個資料行是**「標記」「父系」**,而且都是中繼資料行。這些值可以決定階層。
  • 資料行名稱是以特定方式指定,如本主題稍後所述。
  • 在由此通用資料表產生 XML 時,此資料表中的資料會垂直分割成資料行群組。分組是根據**「標記」**值及資料行名稱來決定。建構 XML 時,處理邏輯會為每個資料列選取一個資料行群組並建構一個元素。以下適用於此範例:
    • 對於第一個資料列中的**「標記」資料行值 1,其名稱包含相同標記編號 Customer!1!cidCustomer!1!name** 的資料行會形成同一個群組。這些資料行是用來處理資料列,而且您可能已注意到產生的元素是 <Customer id=... name=...>。資料行名稱格式會在本主題稍後描述。
    • 對於**「標記」**資料行值 2的資料列,資料行 Order!2!idOrder!2!date 會形成一個群組,之後會用來建構元素 <Order id=... date=... />。
    • 對於**「標記」**資料行值 3,資料行 OrderDetail!3!id!idOrderDetail!3!pid!idref 會形成一個群組。每一個資料列都會由這些資料行產生一個元素 <OrderDetail id=... pid=...>。
  • 請注意,在產生 XML 階層時,會依序處理資料列。決定 XML 階層的方式如下所示:
    • 第一個資料列指定**「標記」值為 1 及「父系」**值為 NULL。因此,對應的元素 (<Customer> 元素) 是新增為 XML 中的最上層元素。

      <Customer cid="C1" name="Janine">
      
    • 第二個資料列識別**「標記」**值為 2 及 **「父系」**值為 1。因此,元素 (<Order> 元素) 是新增為 <Customer> 元素的子項。

      <Customer cid="C1" name="Janine">
         <Order id="O1" date="1/20/1996">
      
    • 下兩個資料列識別**「標記」**值為 3 及 **「父系」**值為 2。因此,會將兩個元素 (<OrderDetail> 元素) 新增為 <Order> 元素的子項。

      <Customer cid="C1" name="Janine">
         <Order id="O1" date="1/20/1996">
            <OrderDetail id="OD1" pid="P1"/>
            <OrderDetail id="OD2" pid="P2"/>
      
    • 最後一個資料列將 2 識別為**「標記」編號,而 1 識別為「父系」**標記編號。因此,會將另一個 <Order> 元素子系新增到 <Customer> 父元素。

      <Customer cid="C1" name="Janine">
         <Order id="O1" date="1/20/1996">
            <OrderDetail id="OD1" pid="P1"/>
            <OrderDetail id="OD2" pid="P2"/>
         </Order>
         <Order id="O2" date="3/29/1997">
      </Customer>
      

簡言之,**「標記」「父系」**中繼資料行中的值、資料行名稱提供的資訊,以及資料列的正確順序都可以在您使用 EXPLICIT 模式時,產生您想要的 XML。

通用資料表資料列順序

在建構 XML 時,會按照順序處理通用資料表中的資料列集。因此,若要擷取與父系相關的正確子執行個體,就必須要將資料列集中的資料列排序,如此每個父節點後面就會緊跟著其所屬子系。

指定通用資料表的資料行名稱

撰寫 EXPLICIT 模式查詢時,必須使用此格式指定所產生資料列集中的資料行名稱。它們可提供轉換資訊,包括使用指示詞指定的元素集屬性名稱和其他資訊在內。

此為一般格式:

ElementName!TagNumber!AttributeName!Directive

以下是格式的部份描述。

  • ElementName
    是產生的元素一般識別碼。例如,如果將 Customers 指定為 ElementName,就會產生 <Customers> 元素。
  • TagNumber
    是指派給元素的唯一標記值。此值搭配兩個中繼資料資料行**「標記」「父系」**,就可以決定結果 XML 中元素的巢狀結構。
  • AttributeName
    提供要建構在指定的 ElementName 中的屬性名稱。如果未指定*「指示詞」*,就會使用這個行為。

    如果指定*「指示詞」*而且它是 xmlcdataelement,就會使用此值建構 ElementName 的元素子系,而且會加入資料行值。

    如果指定*「指示詞」*,AttributeName 可以為空白。例如,ElementName!TagNumber!!Directive。在此情況下,ElementName 會直接包含資料行值。

  • Directive
    *「指示詞」*是選擇性的,而且您可以用以提供建構 XML 的額外資訊。Directive 有兩種用途。

    其中一項用途是將值編碼為 ID、IDREF 及 IDREFS。您可以指定 IDIDREFIDREFS 關鍵字作為*「指示詞」*。這些指示詞會覆寫屬性類型。您可以藉此建立內部文件連結。

    此外,您可以使用*「指示詞」指出要如何將字串資料對應到 XML。hideelement、elementxsinilxmlxmltextcdata 關鍵字可以做為「指示詞」*。hide 指示詞會隱藏節點。只是為了進行排序而擷取值,但不希望產生 XML 時,這就很有用。

    element 指示詞會產生內含元素而不是屬性。內含的資料會被編碼為實體。例如,< 字元會變成 &lt;。對於 NULL 資料行值,不會產生任何元素。如果希望 Null 資料行值會產生一個元素,您可以指定 elementxsinil 指示詞。這將會產生具有屬性 xsi:nil=TRUE 的元素。

    除了不會進行實體編碼之外,xml 指示詞和 element 一樣。請注意,element 指示詞可以與 IDIDREFIDREFS 合併,而 xml 指示詞不能與其他指示詞一起使用,除了 hide 之外。

    cdata 指示詞包含利用 CDATA 區段包裝的資料。內容並未進行實體編碼。原始資料類型必須是文字類型,例如 varcharnvarchartextntext。此指示詞只適用於 hide。使用此指示詞時,絕不能指定 AttributeName

    在大部份情況下,您可以合併這兩個群組織間的指示詞,但不可以合併指示詞本身。

    如果未指定*「指示詞」*及 AttributeName (例如 Customer!1),就會隱含 element 指示詞 (例如 Customer!1!!element),而 ElementName 中會包含資料行資料。

    如果指定 xmltext 指示詞,資料行內容會包裝在單一標記中,與文件的其他部份整合。此指示詞用來取得 OPENXML 儲存在資料行的溢位 (未消耗) XML 資料很有用。如需詳細資訊,請參閱<利用 OPENXML 查詢 XML>。

    如果指定 AttributeName,就會以指定的名稱取代標記名稱。否則,將內容放在不進行實體編碼的內含項目開頭,就會在內含元素目前的屬性清單後面附加上該屬性。具有此指示詞的資料行必須屬於文字類型,例如 varcharnvarcharcharnchartextntext)。此指示詞只適用於 hide。此指示詞可用來取得儲存在資料行的溢位資料。若內容不是完整形成的 XML,則行為是未定義的。

範例

以下為示範 EXPLICIT 模式用法的範例。

A. 擷取員工資訊

此範例會擷取每個員工的員工識別碼及員工名稱。在 AdventureWorks 資料庫中,employeeID 可以從 Employee 資料表取得。員工名稱可以從 Contact 資料表取得。ContactID 資料行可用於聯結資料表。

假設想要 FOR XML EXPLICIT 轉換產生 XML,如下所示:

<Employee EmpID="1" >
  <Name FName="Guy" LName="Gilbert" />
</Employee>
...

因為階層中有兩個層級,所以您要撰寫兩個 SELECT 查詢並套用 UNION ALL。上述為第一個查詢,其會擷取 <Employee> 元素及其屬性的值。查詢將 1 指派為 <Employee> 元素的 **「標記」值,而因為是最上層元素,所以「父系」**為 NULL。

SELECT 1    as Tag,
       NULL as Parent,
       EmployeeID as [Employee!1!EmpID],
       NULL       as [Name!2!FName],
       NULL       as [Name!2!LName]
FROM   HumanResources.Employee E, Person.Contact C
WHERE  E.ContactID = C.ContactID

上述為第二個查詢。它會擷取 <Name> 元素的值。將 <Name> 元素的**「標記」值指派為 2,而可將 <Employee> 識別為父系的「父系」**標記值為 1。

SELECT 2 as Tag,
       1 as Parent,
       EmployeeID,
       FirstName, 
       LastName 
FROM   HumanResources.Employee E, Person.Contact C
WHERE  E.ContactID = C.ContactID

您可以利用 UNION ALL 合併這些查詢,套用 FOR XML EXPLICIT,然後指定所需的 ORDER BY 子句。您必須先按 EmployeeID 排序資料列集,然後再按名稱排列,如此名稱中的 NULL 值才會最先出現。執行以下未使用 FOR XML 子句的查詢,就可以看見產生了通用資料表。

以下為最後查詢:

SELECT 1    as Tag,
       NULL as Parent,
       EmployeeID as [Employee!1!EmpID],
       NULL       as [Name!2!FName],
       NULL       as [Name!2!LName]
FROM   HumanResources.Employee E, Person.Contact C
WHERE  E.ContactID = C.ContactID
UNION ALL
SELECT 2 as Tag,
       1 as Parent,
       EmployeeID,
       FirstName, 
       LastName 
FROM   HumanResources.Employee E, Person.Contact C
WHERE  E.ContactID = C.ContactID
ORDER BY [Employee!1!EmpID],[Name!2!FName]
FOR XML EXPLICIT

以下是部份結果:

<Employee EmpID="1">
  <Name FName="Guy" LName="Gilbert" />
</Employee>
<Employee EmpID="2">
  <Name FName="Kevin" LName="Brown" />
</Employee>
...

第一個 SELECT 會指定結果資料列集中的資料行名稱。這些名稱會形成兩個資料行群組。資料行名稱中有**「標記」**值 1 的群組,可將 Employee 識別為元素,而 EmpID 則識別為屬性。其他資料行群組在資料行中有「標記」值 2,而且可將 <Name> 識別為元素,而 FName 及 LName 則識別為屬性。

下表會顯示此查詢產生的部份資料列集:

Tag Parent  Employee!1!EmpID Name!2!FName Name!2!LName
----------- ----------- ---------------- -------------------
1    NULL     1                NULL          NULL
2     1       1                Guy           Gilbert
1    NULL     2                NULL          NULL
2     1       2                Kevin         Brown
1    NULL     3                NULL          NULL
2     1       3                Roberto       Tamburello 
...

以下是如何處理通用資料表的資料列,以產生結果 XML 樹狀結構:

第一個資料列識別**「標記」值為 1。因此,識別有「標記」**值為 1 的資料行群組 (Employee!1!EmpID)。此資料行會將 Employee 識別為元素名稱。然後就會建立擁有 EmpID 屬性的 <Employee> 元素。將對應的資料行值指派給這些屬性。

第二個資料列的**「標記」值為 2。因此,識別資料行名稱有「標記」值為 2 的資料行群組 (Name!2!FName, Name!2!LName)。這些資料行會將 Name 識別為元素名稱。建立擁有 FName 與 LName 屬性的 <Name> 元素。然後將對應的資料行值指派給這些屬性。此資料列會將 1 識別為「父系」**。就會將此元素子系增加到先前的 <Employee> 元素。

這個處理序會對資料列集中其餘的資料列重複進行。請記下通用資料表中資料列排序的優先順序,如此 FOR XML EXPLICIT 就可以依序處理資料列集,並產生您想要的 XML。

B. 指定 element 指示詞

除了會產生元素中心的 XML 之外,此範例跟範例 A 相似,如下所示:

<Employee EmpID=...>
  <Name>
    <FName>...</FName>
    <LName>...</LName>
  </Name>
</Employee>

除了在資料行名稱中增加 ELEMENT 指示詞之外,該查詢維持不變。因此,<FName> 及 <LName> 元素子系會增加到 <Name> 元素。因為 Employee!1!EmpID 資料行未指定 ELEMENT 指示詞,所以 EmpID 會新增為 <Employee> 元素的屬性。

SELECT 1 as Tag,
       NULL as Parent,
       EmployeeID as [Employee!1!EmpID],
       NULL       as [Name!2!FName!ELEMENT],
       NULL       as [Name!2!LName!ELEMENT]
FROM   HumanResources.Employee E, Person.Contact C
WHERE  E.ContactID = C.ContactID
UNION ALL
SELECT 2 as Tag,
       1 as Parent,
       EmployeeID,
       FirstName, 
       LastName 
FROM   HumanResources.Employee E, Person.Contact C
WHERE  E.ContactID = C.ContactID
ORDER BY [Employee!1!EmpID],[Name!2!FName!ELEMENT]
FOR XML EXPLICIT

以下是部份結果

<Employee EmpID="1">
  <Name>
    <FName>Guy</FName>
    <LName>Gilbert</LName>
  </Name>
</Employee>
<Employee EmpID="2">
  <Name>
    <FName>Kevin</FName>
    <LName>Brown</LName>
  </Name>
</Employee>
...

C. 指定 elementxsinil 指示詞

當您指定 ELEMENT 指示詞擷取元素中心的 XML 時,如果資料行有 NULL 值,EXPLICIT 模式就不會產生與其對應的元素。您可以在 xsi:nil 屬性設為值 TRUE 之處,選擇性地指定 ELEMENTXSINIL 指示詞,要求產生 NULL 值的元素。

以下查詢會建構包括員工地址在內的 XML。對於 AddressLine2 及 City 資料行,資料行名稱會指定 ELEMENTXSINIL 指示詞。這會在資料列集中,為 AddressLine 及 City 資料行中的 NULL 值產生元素。

SELECT 1    as Tag,
       NULL as Parent,
       EmployeeID  as [Employee!1!EmpID],
       E.AddressID as [Employee!1!AddressID],
       NULL        as [Address!2!AddressID],
       NULL        as [Address!2!AddressLine1!ELEMENT],
       NULL        as [Address!2!AddressLine2!ELEMENTXSINIL],
       NULL        as [Address!2!City!ELEMENTXSINIL]
FROM   HumanResources.EmployeeAddress E, Person.Address A
WHERE  E.ContactID = A.ContactID
UNION ALL
SELECT 2 as Tag,
       1 as Parent,
       EmployeeID,
       E.AddressID,
       A.AddressID,
       AddressLine1, 
       AddressLine2,
       City 
FROM   HumanResources.EmployeeAddress E, Person.Address A
WHERE  E.AddressID = A.AddressID
ORDER BY [Employee!1!EmpID],[Address!2!AddressID]
FOR XML EXPLICIT

以下是部份結果:

<Employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        EmpID="1" AddressID="61">
  <Address AddressID="61">
    <AddressLine1>7726 Driftwood Drive</AddressLine1>
    <AddressLine2 xsi:nil="true" />
    <City>Monroe</City>
  </Address>
</Employee>
...

D. 使用 EXPLICIT 模式建構同層級

假設您想要建構提供銷售訂單資訊的 XML。請注意,<SalesPerson> 與 <OrderDetail> 元素為同層級。每個 Order 都有一個 <OrderHeader> 元素、一個 <SalesPerson> 元素,以及一或多個 <OrderDetail> 元素。

<OrderHeader SalesOrderID=... OrderDate=... CustomerID=... >
  <SalesPerson SalesPersonID=... />
  <OrderDetail SalesOrderID=... LineTotal=... ProductID=... OrderQty=... />
  <OrderDetail SalesOrderID=... LineTotal=... ProductID=... OrderQty=.../>
      ...
</OrderHeader>
<OrderHeader ...</OrderHeader>

以下 EXPLICIT 模式查詢會建構此 XML。請注意,查詢指定 <OrderHeader> 元素的**「標記」值為 1,<SalesPerson> 元素為 2,而 <OrderDetail> 元素為 3。因為 <SalesPerson> 及 <OrderDetail> 為同層級,所以查詢會指定同樣可識別 <OrderHeader> 元素的「父系」**標記值 1。

SELECT  1 as Tag,
        0 as Parent,
        SalesOrderID  as [OrderHeader!1!SalesOrderID],
        OrderDate     as [OrderHeader!1!OrderDate],
        CustomerID    as [OrderHeader!1!CustomerID],
        NULL          as [SalesPerson!2!SalesPersonID],
        NULL          as [OrderDetail!3!SalesOrderID],
        NULL          as [OrderDetail!3!LineTotal],
        NULL          as [OrderDetail!3!ProductID],
        NULL          as [OrderDetail!3!OrderQty]
FROM   Sales.SalesOrderHeader
WHERE     SalesOrderID=43659 or SalesOrderID=43661
UNION ALL 
SELECT 2 as Tag,
       1 as Parent,
        SalesOrderID,
        NULL,
        NULL,
        SalesPersonID,  
        NULL,         
        NULL,         
        NULL,
        NULL         
FROM   Sales.SalesOrderHeader
WHERE     SalesOrderID=43659 or SalesOrderID=43661
UNION ALL
SELECT 3 as Tag,
       1 as Parent,
        SOD.SalesOrderID,
        NULL,
        NULL,
        SalesPersonID,
        SOH.SalesOrderID,
        LineTotal,
        ProductID,
        OrderQty   
FROM    Sales.SalesOrderHeader SOH,Sales.SalesOrderDetail SOD
WHERE   SOH.SalesOrderID = SOD.SalesOrderID
AND     (SOH.SalesOrderID=43659 or SOH.SalesOrderID=43661)
ORDER BY [OrderHeader!1!SalesOrderID], [SalesPerson!2!SalesPersonID],
         [OrderDetail!3!SalesOrderID],[OrderDetail!3!LineTotal]
FOR XML EXPLICIT

以下是部份結果:

<OrderHeader SalesOrderID="43659" OrderDate="2001-07-01T00:00:00" CustomerID="676">
  <SalesPerson SalesPersonID="279" />
  <OrderDetail SalesOrderID="43659" LineTotal="10.373000" ProductID="712" OrderQty="2" />
  <OrderDetail SalesOrderID="43659" LineTotal="28.840400" ProductID="716" OrderQty="1" />
  <OrderDetail SalesOrderID="43659" LineTotal="34.200000" ProductID="709" OrderQty="6" />
   ...
</OrderHeader>
<OrderHeader SalesOrderID="43661" OrderDate="2001-07-01T00:00:00" CustomerID="442">
  <SalesPerson SalesPersonID="282" />
  <OrderDetail SalesOrderID="43661" LineTotal="20.746000" ProductID="712" OrderQty="4" />
  <OrderDetail SalesOrderID="43661" LineTotal="40.373000" ProductID="711" OrderQty="2" />
   ...
</OrderHeader>

E. 指定 ID、IDREF 指示詞

此範例與範例 C 相同。唯一不同的是,查詢指定 ID、IDREF 指示詞。這些指示詞會覆寫 <OrderHeader> 及 <OrderDetail> 元素中的 SalesPersonID 屬性類型。這會形成內部文件連結。您需要結構描述才能查看被覆寫的類型。因此、查詢會在 FOR XML 子句中指定 XMLDATA 選項,以擷取結構描述。

SELECT  1 as Tag,
        0 as Parent,
        SalesOrderID  as [OrderHeader!1!SalesOrderID!id],
        OrderDate     as [OrderHeader!1!OrderDate],
        CustomerID    as [OrderHeader!1!CustomerID],
        NULL          as [SalesPerson!2!SalesPersonID],
        NULL          as [OrderDetail!3!SalesOrderID!idref],
        NULL          as [OrderDetail!3!LineTotal],
        NULL          as [OrderDetail!3!ProductID],
        NULL          as [OrderDetail!3!OrderQty]
FROM   Sales.SalesOrderHeader
WHERE  SalesOrderID=43659 or SalesOrderID=43661
UNION ALL 
SELECT 2 as Tag,
       1 as Parent,
        SalesOrderID, 
        NULL,
        NULL,
        SalesPersonID,  
        NULL,         
        NULL,         
        NULL,
        NULL         
FROM   Sales.SalesOrderHeader
WHERE  SalesOrderID=43659 or SalesOrderID=43661
UNION ALL
SELECT 3 as Tag,
       1 as Parent,
        SOD.SalesOrderID,
        NULL,
        NULL,
        SalesPersonID,
        SOH.SalesOrderID,
        LineTotal,
        ProductID,
        OrderQty   
FROM    Sales.SalesOrderHeader SOH,Sales.SalesOrderDetail SOD
WHERE   SOH.SalesOrderID = SOD.SalesOrderID
AND     (SOH.SalesOrderID=43659 or SOH.SalesOrderID=43661)
ORDER BY [OrderHeader!1!SalesOrderID!id], [SalesPerson!2!SalesPersonID],
         [OrderDetail!3!SalesOrderID!idref],[OrderDetail!3!LineTotal]
FOR XML EXPLICIT, XMLDATA

以下是部份結果。請注意在結構描述中,IDIDREF 指示詞已覆寫 <OrderHeader> and <OrderDetail> 元素中 SalesOrderID 屬性的資料類型。如果您移除這些指示詞,結構描述就會傳回這些屬性的原始類型。

<Schema name="Schema1" xmlns="urn:schemas-microsoft-com:xml-data" xmlns:dt="urn:schemas-microsoft-com:datatypes">
  <ElementType name="OrderHeader" content="mixed" model="open">
    <AttributeType name="SalesOrderID" dt:type="id" />
    <AttributeType name="OrderDate" dt:type="dateTime" />
    <AttributeType name="CustomerID" dt:type="i4" />
    <attribute type="SalesOrderID" />
    <attribute type="OrderDate" />
    <attribute type="CustomerID" />
  </ElementType>
  <ElementType name="SalesPerson" content="mixed" model="open">
    <AttributeType name="SalesPersonID" dt:type="i4" />
    <attribute type="SalesPersonID" />
  </ElementType>
  <ElementType name="OrderDetail" content="mixed" model="open">
    <AttributeType name="SalesOrderID" dt:type="idref" />
    <AttributeType name="LineTotal" dt:type="number" />
    <AttributeType name="ProductID" dt:type="i4" />
    <AttributeType name="OrderQty" dt:type="i2" />
    <attribute type="SalesOrderID" />
    <attribute type="LineTotal" />
    <attribute type="ProductID" />
    <attribute type="OrderQty" />
  </ElementType>
</Schema>
<OrderHeader xmlns="x-schema:#Schema1" SalesOrderID="43659" OrderDate="2001-07-01T00:00:00" CustomerID="676">
  <SalesPerson SalesPersonID="279" />
  <OrderDetail SalesOrderID="43659" LineTotal="10.373000" ProductID="712" OrderQty="2" />
  ...
</OrderHeader>
...

F. 指定 ID、IDREFS 指示詞

元素屬性可以指定為 ID 類型屬性,然後可以使用 IDREFS 屬性來參考它。這會啟用內部文件連結,而且是跟關聯式資料庫中的主索引鍵及外部索引鍵關聯性類似。

此範例說明如何使用 IDIDREFS 指示詞,建立 IDIDREFS 類型的屬性。因為 ID 不能是整數值,所以此範例中的 ID 值會經過轉換。換句話說是經過類型轉換。ID 值會使用前置詞。

假設您想要建構如下所示的 XML:

<Customer CustomerID="C1" SalesOrderIDList=" O11 O22 O33..." >
    <SalesOrder SalesOrderID="O11" OrderDate="..." />
    <SalesOrder SalesOrderID="O22" OrderDate="..." />
    <SalesOrder SalesOrderID="O33" OrderDate="..." />
    ...
</Customer>

< Customer > 元素的 SalesOrderIDList 屬性是多重值屬性,會參考到 < SalesOrder > 元素的 SalesOrderID 屬性。若要建立此連結,SalesOrderID 屬性必須宣告為 ID 類型,而且 <Customer> 元素的 SalesOrderIDList 屬性必須宣告為 IDREFS 類型。因為一位客戶可以下多份訂單,所以要使用 IDREFS 類型。

IDREFS 也可以擁有多個值。因此,您必須使用個別的 select 子句,重複使用相同的標記、父系及索引鍵資料行資訊。然後 ORDER BY 必須確定構成 IDREFS 值的資料列順序,在它們的父成員下會分在同一組。

以下查詢會產生您想要的 XML。此查詢使用 IDIDREFS 指示詞覆寫資料行名稱 (SalesOrder!2!SalesOrderID!ID, Customer!1!SalesOrderIDList!IDREFS) 中的類型。

SELECT  1 as Tag,
        0 as Parent,
        C.CustomerID       [Customer!1!CustomerID],
        NULL               [Customer!1!SalesOrderIDList!IDREFS],
        NULL               [SalesOrder!2!SalesOrderID!ID],
        NULL               [SalesOrder!2!OrderDate]
FROM   Sales.Customer C 
UNION ALL 
SELECT  1 as Tag,
        0 as Parent,
        C.CustomerID,
        'O-'+CAST(SalesOrderID as varchar(10)), 
        NULL,
        NULL
FROM   Sales.Customer C, Sales.SalesOrderHeader SOH
WHERE  C.CustomerID = SOH.CustomerID
UNION ALL
SELECT 2 as Tag,
       1 as Parent,
        C.CustomerID,
        NULL,
        'O-'+CAST(SalesOrderID as varchar(10)),
        OrderDate
FROM   Sales.Customer C, Sales.SalesOrderHeader SOH
WHERE  C.CustomerID = SOH.CustomerID
ORDER BY [Customer!1!CustomerID] ,
         [SalesOrder!2!SalesOrderID!ID],
         [Customer!1!SalesOrderIDList!IDREFS]
FOR XML EXPLICIT

G. 使用 hide 指示詞隱藏結果 XML 的元素及屬性

此範例說明 hide 指示詞的用法。當您希望查詢可以傳回由查詢傳回的通用資料表中,用以排序資料列的屬性,但又不希望在最後的結果 XML 文件中看見該屬性時,此指示詞就相當有用。

此查詢會建構以下 XML:

<ProductModel ProdModelID="19" Name="Mountain-100">
  <Summary>
    <SummaryDescription>
           <Summary> element from XML stored in CatalogDescription column
    </SummaryDescription>
  </Summary>
</ProductModel>

此查詢會產生您想要的 XML。查詢可識別出資料行名稱中標記值各為 1 及 2 的兩個資料行群組。

此查詢使用 xml 資料類型的 query() 方法 (xml 資料類型),查詢 xml 類型的 CatalogDescription 資料行,以擷取摘要描述。此查詢也可以使用 xml 資料類型的 value() 方法 (xml 資料類型),擷取 CatalogDescription 資料行的 ProductModelID 值。結果 XML 中不需要有此值,但必須要有此值才能將產生的資料列集排序。因此,資料行名稱 [Summary!2!ProductModelID!hide] 包括 hide 指示詞在內。如果 SELECT 陳述式中不包括此資料行,您將必須按 [ProductModel!1!ProdModelID] 及 [Summary!2!SummaryDescription] (此為xml 類型) 排序資料列集,而且無法以 ORDER BY 使用 xml 類型資料行。因此,會增加額外的 [Summary!2!ProductModelID!hide] 資料行,然後以 ORDER BY 子句指定。

SELECT  1 as Tag,
        0 as Parent,
        ProductModelID     as [ProductModel!1!ProdModelID],
        Name               as [ProductModel!1!Name],
        NULL               as [Summary!2!ProductModelID!hide],
        NULL               as [Summary!2!SummaryDescription]
FROM    Production.ProductModel
WHERE   CatalogDescription is not null
UNION ALL
SELECT  2 as Tag,
        1 as Parent,
        ProductModelID,
        Name,
        CatalogDescription.value('
         declare namespace PD="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
       (/PD:ProductDescription/@ProductModelID)[1]', 'int'),
        CatalogDescription.query('
         declare namespace pd="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
         /pd:ProductDescription/pd:Summary')
FROM    Production.ProductModel
WHERE   CatalogDescription is not null
ORDER BY [ProductModel!1!ProdModelID],[Summary!2!ProductModelID!hide]
FOR XML EXPLICIT
go

以下是結果:

<ProductModel ProdModelID="19" Name="Mountain-100">
  <Summary>
    <SummaryDescription>
      <pd:Summary xmlns:pd="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription" >
        <p1:p xmlns:p1="http://www.w3.org/1999/xhtml">Our top-of-the-line competition mountain bike. Performance-enhancing options include the innovative HL Frame, super-smooth front suspension, and traction for all terrain. </p1:p>
      </pd:Summary>
    </SummaryDescription>
  </Summary>
</ProductModel>

H. 指定 element 指示詞及實體編碼

此範例說明 elementxml 指示詞之間的相異處。element 指示詞會將資料實體化,但 xml 指示詞則否。已將 <Summary> 元素指派給查詢中的 XML <Summary>This is summary description</Summary>

請參考這個查詢:

SELECT  1 as Tag,
        0 as Parent,
        ProductModelID  as [ProductModel!1!ProdModelID],
        Name            as [ProductModel!1!Name],
        NULL            as [Summary!2!SummaryDescription!ELEMENT]
FROM    Production.ProductModel
WHERE   ProductModelID=19
UNION ALL
SELECT  2 as Tag,
        1 as Parent,
        ProductModelID,
        NULL,
       '<Summary>This is summary description</Summary>'
FROM   Production.ProductModel
WHERE  ProductModelID=19
FOR XML EXPLICIT

以下是結果。摘要描述會在結果中實體化。

<ProductModel ProdModelID="19" Name="Mountain-100">
  <Summary>
    <SummaryDescription>&lt;Summary&gt;This is summary description&lt;/Summary&gt;</SummaryDescription>
  </Summary>
</ProductModel>

現在,如果您在資料行名稱 Summary!2!SummaryDescription!xml 中指定 xml 指示詞,而非 element 指示詞,您將會收到未實體化的摘要描述。

<ProductModel ProdModelID="19" Name="Mountain-100">
  <Summary>
    <SummaryDescription>
      <Summary>This is summary description</Summary>
    </SummaryDescription>
  </Summary>
</ProductModel>

以下查詢不會指派靜態的 XML 值,而是使用 xml 類型的 query() 方法,擷取 xml 類型之 CatalogDescription 資料行的產品型號摘要描述。因為已知結果將為 xml 類型,所以不會套用實體化。

SELECT  1 as Tag,
        0 as Parent,
        ProductModelID  as [ProductModel!1!ProdModelID],
        Name            as [ProductModel!1!Name],
        NULL            as [Summary!2!SummaryDescription]
FROM    Production.ProductModel
WHERE   CatalogDescription is not null
UNION ALL
SELECT  2 as Tag,
        1 as Parent,
        ProductModelID,
        Name,
       (SELECT CatalogDescription.query('
            declare namespace pd="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
          /pd:ProductDescription/pd:Summary'))
FROM     Production.ProductModel
WHERE    CatalogDescription is not null
ORDER BY [ProductModel!1!ProdModelID],Tag
FOR XML EXPLICIT

I. 指定 cdata 指示詞

如果指示詞設為 cdata,包含的資料將不會進行實體編碼,但會放在 CDATA 區段中。cdata 屬性必須沒有名稱。

以下查詢會將產品型號摘要描述包裝在 CDATA 區段中。

SELECT  1 as Tag,
        0 as Parent,
        ProductModelID  as [ProductModel!1!ProdModelID],
        Name            as [ProductModel!1!Name],
        '<Summary>This is summary description</Summary>'   
            as [ProductModel!1!!cdata] -- no attribute name so ELEMENT assumed
FROM    Production.ProductModel
WHERE   ProductModelID=19
FOR XML EXPLICIT

以下是結果:

<ProductModel ProdModelID="19" Name="Mountain-100">
   <![CDATA[<Summary>This is summary description</Summary>]]>
</ProductModel>

I. 指定 xmltext 指示詞

此範例說明如何在使用 SELECT 陳述式的 EXPLICIT 模式中,使用 xmltext 指示詞將溢位資料行的資料定址。

考慮 Person 資料表。此資料表有 Overflow 資料行,可用來儲存 XML 文件的未消耗部份。

CREATE TABLE Person(PersonID varchar(5), PersonName varchar(20), Overflow nvarchar(200))
INSERT INTO Person VALUES ('P1','Joe',N'<SomeTag attr1="data">content</SomeTag>')
INSERT INTO Person VALUES ('P2','Joe',N'<SomeTag attr2="data"/>')
INSERT INTO Person VALUES ('P3','Joe',N'<SomeTag attr3="data" PersonID="P">content</SomeTag>')

此查詢從 Person 資料表擷取資料行。對於 Overflow 資料行,並未指定 AttributeName,但*「指示詞」*會將 xmltext 設為提供通用資料表資料行名稱的一部份。

SELECT 1 as Tag, NULL as parent,
       PersonID as [Parent!1!PersonID],
       PersonName as [Parent!1!PersonName],
       overflow as [Parent!1!!xmltext] -- No AttributeName; xmltext directive
FROM Person
FOR XML EXPLICIT

產生 XML 文件:

  • 因為 Overflow 資料行未指定 AttributeName,但指定 xmltext 指示詞,所以 <overflow> 元素中的屬性會附加到封閉式 <Parent> 元素的屬性清單。
  • 因為 <xmltext> 元素中的 PersonID 屬性跟在相同元素層級上擷取的 PersonID 屬性衝突,所以即使 PersonID 為 NULL,還是會忽略 <xmltext> 元素中的屬性。一般而言,屬性會覆寫溢位中相同名稱的屬性。

結果如下:

<Parent PersonID="P1" PersonName="Joe" attr1="data">content</Parent>
<Parent PersonID="P2" PersonName="Joe" attr2="data"></Parent>
<Parent PersonID="P3" PersonName="Joe" attr3="data">content</Parent>

如果溢位資料有子元素而且指定相同的查詢,則 Overflow 資料行中的子元素將會新增為封閉式 <Parent> 元素的子元素。

例如,變更 Person 資料表中的資料,使得 Overflow 資料行現在具有子元素。

TRUNCATE TABLE Person
INSERT INTO Person VALUES ('P1','Joe',N'<SomeTag attr1="data">content</SomeTag>')
INSERT INTO Person VALUES ('P2','Joe',N'<SomeTag attr2="data"/>')
INSERT INTO Person VALUES ('P3','Joe',N'<SomeTag attr3="data" PersonID="P"><name>PersonName</name></SomeTag>')

如果執行相同的查詢,則 <xmltext> 元素中的子元素將會新增為封閉式 <Parent> 元素的子元素。

SELECT 1 as Tag, NULL as parent,
       PersonID as [Parent!1!PersonID],
       PersonName as [Parent!1!PersonName],
       overflow as [Parent!1!!xmltext] -- no AttributeName, xmltext directive
FROM Person
FOR XML EXPLICIT

以下是結果:

<Parent PersonID="P1" PersonName="Joe" attr1="data">content</Parent>
<Parent PersonID="P2" PersonName="Joe" attr2="data"></Parent>
<Parent PersonID="P3" PersonName="Joe" attr3="data">
  <name>PersonName</name>
</Parent>

如果以 xmltext 指示詞指定 AttributeName,則 <overflow> 元素的屬性將會新增為封閉式 <Parent> 元素的子元素屬性。為 AttributeName 所指定的名稱將成為子元素的名稱。

在此查詢中,AttributeName (<overflow>) 是以 xmltext 指示詞一起指定:**

SELECT 1 as Tag, NULL as parent,
       PersonID as [Parent!1!PersonID],
       PersonName as [Parent!1!PersonName],
       overflow as [Parent!1!overflow!xmltext] -- overflow is AttributeName
                      -- xmltext is directive
FROM Person
FOR XML EXPLICIT

以下是結果:

<Parent PersonID="P1" PersonName="Joe">
  <overflow attr1="data">content</overflow>
</Parent>
<Parent PersonID="P2" PersonName="Joe">
  <overflow attr2="data" />
</Parent>
<Parent PersonID="P3" PersonName="Joe">
  <overflow attr3="data" PersonID="P">
    <name>PersonName</name>
  </overflow>
</Parent>

在此查詢元素中,PersonName 屬性指定為 directivePersonName 的結果將會新增為封閉式 <Parent> 元素的子元素。<xmltext> 的屬性仍然會附加到封閉式 <Parent> 元素。<overflow> 元素的內容 (子元素) 將會附加到封閉式 <Parent> 元素的其他子元素前面。

SELECT 1      as Tag, NULL as parent,
       PersonID   as [Parent!1!PersonID],
       PersonName as [Parent!1!PersonName!element], -- element directive
       overflow   as [Parent!1!!xmltext]
FROM Person
FOR XML EXPLICIT

以下是結果:

<Parent PersonID="P1" attr1="data">content<PersonName>Joe</PersonName>
</Parent>
<Parent PersonID="P2" attr2="data">
  <PersonName>Joe</PersonName>
</Parent>
<Parent PersonID="P3" attr3="data">
  <name>PersonName</name>
  <PersonName>Joe</PersonName>
</Parent>

如果 xmltext 資料行資料包含根元素的屬性,這些屬性不會顯示於 XML 資料結構描述中,而且 MSXML 剖析器 (Parser) 並不會驗證產生的 XML 文件片段。例如:

SELECT 1 as Tag,
       0 as Parent,
       N'<overflow a="1"/>' as 'overflow!1!!xmltext'
FOR XML EXPLICIT, xmldata

以下是結果。請注意,在傳回的結構描述中,結構描述已經遺漏溢位屬性 a

<Schema name="Schema2" 
        xmlns="urn:schemas-microsoft-com:xml-data" 
        xmlns:dt="urn:schemas-microsoft-com:datatypes">
  <ElementType name="overflow" content="mixed" model="open">
  </ElementType>
</Schema>
<overflow xmlns="x-schema:#Schema2" a="1">
</overflow> 

請參閱

參考

使用 RAW 模式
使用 AUTO 模式
使用 FOR XML 建構 XML

概念

使用 PATH 模式

其他資源

SELECT (Transact-SQL)

說明及資訊

取得 SQL Server 2005 協助