EXPLICIT 모드 사용

FOR XML을 사용하는 XML 생성 항목에 설명된 것과 같이 RAW 및 AUTO 모드에서는 쿼리 결과로 생성되는 XML의 모양을 상세하게 조정할 수 없습니다. 하지만 EXPLICIT 모드에서는 쿼리 결과로 생성되는 XML의 모양을 좀 더 상세하게 조정할 수 있습니다.

XML에 예상되는 중첩과 같은 필수 XML에 대한 추가 정보는 쿼리의 일부로 명시적으로 지정하는 방식으로 EXPLICIT 모드 쿼리를 작성해야 합니다. 요청한 XML에 따라 EXPLICIT 모드 쿼리를 작성하는 작업은 복잡할 수 있습니다. EXPLICIT 모드 쿼리를 작성하는 것보다는 PATH 모드 사용의 설명에 따라 중첩을 사용하는 것이 더 간단합니다.

EXPLICIT 모드에서 쿼리의 일부로 원하는 XML을 기술하기 때문에 생성된 XML은 형식이 올바르고 유효해야 합니다.

EXPLICIT 모드의 행 집합 처리

EXPLICIT 모드는 쿼리 실행으로부터 만들어지는 행 집합을 XML 문서로 변환합니다. EXPLICIT 모드의 경우 XML문서를 만들기 위해서는 행 집합이 특정 형식을 가져야 합니다. 이를 위해서는 처리 논리에서 원하는 XML을 생성할 수 있도록 특정 형식을 지닌 행 집합인 범용 테이블을 생성하는 SELECT 쿼리를 작성해야 합니다.

먼저 쿼리는 다음 두 메타데이터 열을 생성해야 합니다.

  • 첫 번째 열은 현재 요소에 대한 정수 형식의 태그 번호를 제공해야 하며 열 이름은 Tag여야 합니다. 쿼리에서는 행 집합으로부터 생성될 각 요소의 고유 태그 번호를 제공해야 합니다.
  • 두 번째 열은 부모 요소의 태그 번호를 제공해야 하며 이 열 이름은 Parent여야 합니다. 이러한 빙식으로 Tag 및 Parent 열은 계층 정보를 제공합니다.

이러한 메타데이터 열 값은 열 이름의 정보와 함께 원하는 XML을 생성하는 데 사용됩니다. 쿼리에서는 특정 방식으로 열 이름을 제공해야 합니다. 또한 Parent 열에 있는 0 또는 NULL은 해당 요소에 부모가 없음을 나타냅니다. 요소는 최상위 요소로 XML에 추가됩니다.

쿼리에 의해 생성된 범용 열이 XML 결과를 생성하도록 처리되는 방법을 이해하려면 이 범용 테이블을 생성하는 쿼리를 작성했다고 가정해 보십시오.

예제 범용 테이블

이 범용 테이블에 대해 다음 사항을 유의하십시오.

  • 처음 두 열은 TagParent이며 메타 열입니다. 이러한 값은 계층을 결정합니다.
  • 열 이름은 이 항목의 후반에 설명된 바와 같은 특정 방식으로 지정됩니다.
  • 이 범용 테이블로부터 XML을 생성할 때 이 테이블의 데이터는 열 그룹으로 수직 분할됩니다. 그룹화는 Tag 값 및 열 이름에 따라 결정됩니다. XML을 생성할 때 처리 논리는 각 행에 대해 하나의 열 그룹을 선택하고 요소를 생성합니다. 이 예에서는 다음 사항이 적용됩니다.
    • 첫 번째 행에 있는 Tag 열 값 1에 대해 이름에 동일한 태그 번호 Customer!1!cidCustomer!1!name이 포함된 열은 하나의 그룹을 형성합니다. 이러한 열은 행을 처리하는 데 사용되며 생성된 요소의 모양은 <Customer id=... name=...>임을 알 수 있습니다. 열 이름 형식은 이 항목의 후반에 설명됩니다.
    • Tag 열 값이 2인 행에 대해 Order!2!idOrder!2!date 열은 이후에 <Order id=... date=... /> 요소를 생성하는 데 사용되는 그룹을 형성합니다.
    • Tag 열 값이 3인 행에 대해 OrderDetail!3!id!idOrderDetail!3!pid!idref 열은 그룹을 형성합니다. 이러한 각 행은 이러한 열로부터 <OrderDetail id=... pid=...> 요소를 생성합니다.
  • XML 계층을 생성할 때 행은 순서대로 처리됩니다. XML 계층은 다음과 같이 결정됩니다.
    • 첫 번째 행은 Tag 값 1과 Parent 값 NULL을 지정합니다. 따라서 해당 요소인 <Customer> 요소는 XML에서 최상위 요소로 추가됩니다.

      <Customer cid="C1" name="Janine">
      
    • 두 번째 행은 Tag 값 2와 Parent 값 1을 식별합니다. 따라서 <Order> 요소는 <Customer> 요소의 자식으로 추가됩니다.

      <Customer cid="C1" name="Janine">
         <Order id="O1" date="1/20/1996">
      
    • 다음 두 행은 Tag 값 3과 Parent 값 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"/>
      
    • 마지막 행은 Tag 번호로 2를 식별하고 Parent 태그 번호로 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 모드에서는 TagParent 메타 열의 값과 열 이름에 제공된 정보 및 행의 올바른 순서로 원하는 XML이 생성됩니다.

범용 테이블 행 순서 지정

XML을 생성할 때 범용 테이블의 행은 순서대로 처리됩니다. 따라서 해당 부모와 연결된 올바른 자식 요소를 검색하려면 각 부모 노드 바로 다음에 해당 자식 노드가 오도록 행 집합의 행 순서를 지정해야 합니다.

범용 테이블에 열 이름 지정

EXPLICIT 모드 쿼리를 작성할 때 결과 행 집합에 있는 열 이름은 다음 형식에 따라 지정되어야 합니다. 이러한 형식은 지시어를 사용하여 지정된 요소 및 특성 이름과 기타 추가 정보를 포함하는 변환 정보를 제공합니다.

일반 형식은 다음과 같습니다.

ElementName!TagNumber!AttributeName!Directive

다음은 형식의 각 부분에 대한 설명입니다.

  • ElementName
    요소의 일반적인 결과 식별자입니다. 예를 들어 CustomersElementName으로 지정된 경우 <Customers> 요소가 생성됩니다.
  • TagNumber
    요소에 할당된 고유 태그 값입니다. 이 값은 두 메타데이터 열인 TagParent를 통해 결과 XML에서의 요소 중첩을 결정합니다.
  • AttributeName
    지정된 ElementName을 생성하기 위해 특성 이름을 제공합니다. 이 동작은 Directive가 지정되지 않은 경우의 동작입니다.

    Directive가 지정되어 있고 xml, cdata 또는 element인 경우 이 값은 ElementName의 요소 자식을 생성하는 데 사용되고 열 값이 여기에 추가됩니다.

    Directive를 지정하면 AttributeName을 비워 둘 수 있습니다. 예를 들면 ElementName!TagNumber!!Directive와 같습니다. 이 경우 열 값은 ElementName에 직접 포함됩니다.

  • Directive
    Directive는 선택 항목으로서 XML 생성을 위한 추가 정보를 제공하는 데 사용할 수 있습니다. Directive에는 두 가지 용도가 있습니다.

    하나는 값을 ID, IDREF 및 IDREFS로 인코딩하는 것입니다. ID, IDREFIDREFS 키워드를 Directive로 지정할 수 있습니다. 이러한 지시어는 특성 유형을 덮어씁니다. 이렇게 하면 문서 간 연결을 만들 수 있습니다.

    또한 Directive를 사용하여 문자열 데이터를 XML로 매핑하는 방법을 나타낼 수 있습니다. hide, element, elementxsinil, xml, xmltextcdata 키워드는 Directive로 사용될 수 있습니다. hide 지시어는 노드를 숨깁니다. 이 키워드는 정렬 목적으로만 값을 검색하고 결과 XML에는 표시되지 않도록 하려는 경우에 유용합니다.

    element 지시어는 특성 대신 포함된 요소를 생성합니다. 포함된 데이터는 엔터티로 인코딩됩니다. 예를 들어 < 문자는 &lt;가 됩니다. NULL 열 값에 대해 경우 요소가 생성되지 않습니다. Null 열 값에 대해 요소를 생성하려면 elementxsinil 지시어를 지정합니다. 이렇게 하면 특성이 xsi:nil=TRUE인 요소가 생성됩니다.

    xml 지시어는 element 지시어와 비슷하지만 엔터티 인코딩이 발생하지 않는다는 점이 다릅니다. element 지시어는 ID, IDREF 또는 IDREFS와 조합될 수 있지만 xml 지시어는 hide를 제외한 다른 지시어와는 조합될 수 없습니다.

    cdata 지시어는 CDATA 섹션으로 데이터를 묶어서 포함시킵니다. 내용은 인코딩된 엔터티가 아닙니다. 원래 데이터 형식은 varchar, nvarchar, text 또는 ntext와 같은 텍스트 유형이어야 합니다. 이 지시어와 함께 사용할 수 있는 것은 hide뿐입니다. 이 지시어를 사용할 때는 AttributeName을 지정하지 말아야 합니다.

    이러한 두 그룹 간 지시어 조합은 대부분의 경우 허용되지만 자체 그룹에서 지시어를 조합하는 것은 허용되지 않습니다.

    Customer!1과 같은 DirectiveAttributeName이 지정되지 않은 경우 Customer!1!!element와 같은 element 지시어가 내포되고 열 데이터가 ElementName에 포함됩니다.

    xmltext 지시어가 지정된 경우 열 내용은 문서의 나머지 부분에 통합된 단일 태그로 묶입니다. 이 지시어는 OPENXML에 의해 열에 저장된 사용되지 않은 오버플로 XML 데이터를 인출하는 데 유용합니다. 자세한 내용은 OPENXML을 사용하여 XML 쿼리를 참조하십시오.

    AttributeName이 지정된 경우 태그 이름이 지정된 이름으로 바뀝니다. 그렇지 않으면 엔터티 인코딩 없이 포함 내용의 시작 위치에 내용을 배치하여 묶는 요소의 현재 특성 목록에 특성이 포함됩니다. 이 지시어가 있는 열은 varchar, nvarchar, char, nchar, text 또는 ntext와 같은 텍스트 유형이어야 합니다. 이 지시어와 함께 사용할 수 있는 것은 hide뿐입니다. 이 지시어는 열에 저장된 오버플로 데이터를 인출하는 데 유용합니다. 내용이 잘 작성된 XML이 아니면 동작이 정의되지 않습니다.

다음은 EXPLICIT 모드 사용 방법을 보여 주는 예입니다.

1. 직원 정보 검색

이 예에서는 각 직원에 대한 직원 ID와 직원 이름을 검색합니다. AdventureWorks 데이터베이스에서 employeeID는 Employee 테이블로부터 가져올 수 있습니다. 직원 이름은 Contact 테이블로부터 가져올 수 있습니다. ContactID 열을 사용하면 테이블을 조인할 수 있습니다.

FOR XML EXPLICIT 변환으로 다음과 같이 XML을 생성한다고 가정해 보십시오.

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

계층에 두 수준이 있기 때문에 두 개의 SELECT 쿼리를 작성하고 UNION ALL을 적용합니다. 이 쿼리는 <Employee> 요소에 대한 값과 해당 특성을 검색하는 첫 번째 쿼리입니다. 이 쿼리는 <Employee> 요소에 대한 Tag 값으로 1을 할당하고 최상위 요소이기 때문에 Parent에는 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> 요소에 대한 Tag 값으로 2를 할당하고 <Employee>를 부모로 지정하는 Parent 태그 값으로 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는 결과 행 집합에 대해 열 이름을 지정합니다. 이러한 이름은 두 개의 열 그룹을 형성합니다. 열 이름에서 Tag 값이 1인 그룹은 Employee를 요소로, EmpID는 특성으로 식별합니다. 다른 열 그룹에는 열에 Tag 값 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 트리를 생성하는 방법을 보여 줍니다.

첫 번째 행은 Tag 값 1을 식별합니다. 따라서 Tag 값 1이 있는 열 그룹은 Employee!1!EmpID로 식별됩니다. 이 열은 Employee를 요소 이름으로 식별합니다. 그런 다음 EmpID 특성이 포함된 <Employee> 요소가 생성됩니다. 이러한 특성에는 해당 열 값이 할당됩니다.

두 번째 행에는 Tag 값 2가 포함됩니다. 따라서 열 이름에 Tag 값 2가 포함된 열 그룹 Name!2!FName 및 Name!2!LName이 식별됩니다. 이러한 열 이름은 Name을 요소 이름으로 식별합니다. FName 및 LName 특성이 포함된 <Name> 요소가 생성됩니다. 이러한 특성에는 해당 열 값이 할당됩니다. 이 행은 1을 Parent로 식별합니다. 이 요소 자식은 이전 <Employee> 요소에 추가됩니다.

이러한 프로세스는 행 집합의 남은 열에 대해 반복됩니다. FOR XML EXPLICIT에서 행 집합을 순서대로 처리하고 원하는 XML을 생성하기 위해서는 범용 테이블의 행을 정렬하는 것이 중요합니다.

2. 요소 지시어 지정

이 예는 다음과 같이 요소 중심 XML을 생성한다는 점을 제외하고는 예 1과 비슷합니다.

<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>
...

3. elementxsinil 지시어 지정

요소 중심 XML을 검색하기 위해 ELEMENT 지시어를 지정할 때 열에 NULL 값이 있으면 EXPLICIT 모드에서 해당 요소가 생성되지 않습니다. xsi:nil 특성이 TRUE 값으로 설정된 경우 NULL 값에 대한 요소를 생성하도록 요청하기 위해 선택적으로 ELEMENTXSINIL 지시어를 지정할 수 있습니다.

다음 쿼리는 직원 주소가 포함된 XML을 생성합니다. AddressLine2 및 City 열에서 열 이름은 ELEMENTXSINIL 지시어를 지정합니다. 이렇게 하면 행 집합에서 AddressLine2 및 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>
...

4. 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> 요소, <SalesPerson> 요소 및 <OrderDetail> 요소에 대해 Tag 값을 각각 1, 2 및 3으로 지정합니다. <SalesPerson>과 <OrderDetail>은 형제이기 때문에 이 쿼리는 같은 Parent 태그 값으로 1을 지정하여 <OrderHeader> 요소를 식별합니다.

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>

5. ID, IDREF 지시어 지정

이 예는 예 3과 동일하지만 이 쿼리에서는 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

다음은 결과의 일부입니다. 스키마에서 ID, IDREF 지시어는 <OrderHeader> 및 <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>
...

6. 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을 생성합니다. 이 쿼리는 ID, IDREFS 지시어를 사용하여 열 이름(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

7. 결과 XML에서 요소 및 특성을 숨기기 위해 hide 지시어 사용

이 예에서는 hide 지시어 사용 방법을 보여 줍니다. 이 지시어는 쿼리에 의해 반환된 범용 테이블의 행을 정렬하기 위한 특성은 쿼리가 반환하게 하고 최종 결과 XML 문서에는 그 특성이 포함되지 않게 하려는 경우에 유용합니다.

다음 쿼리는 이러한 XML을 생성합니다.

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

이 쿼리는 원하는 XML을 생성합니다. 이 쿼리는 열 이름의 Tag 값으로 1과 2가 포함된 두 열 그룹을 식별합니다.

이 쿼리는 xml 데이터 형식의 query() 메서드(xml 데이터 형식)를 사용하여 요약 설명을 검색하기 위해 xml 유형의 CatalogDescription 열을 쿼리합니다. 이 쿼리는 또한 xml 데이터 형식의 value() 메서드(xml 데이터 형식)를 사용하여 CatalogDescription 열로부터 ProductModelID 값을 검색합니다. 이 값은 결과 XML에 필요하지 않지만 결과 행 집합을 정렬하는 데 필요합니다. 따라서 열 이름 [Summary!2!ProductModelID!hide]에는 hide 지시어가 포함됩니다. 이 열이 SELECT 문에 포함되지 않은 경우 xml 유형인 [ProductModel!1!ProdModelID] 및 [Summary!2!SummaryDescription]으로 행 집합을 정렬해야 하며 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>

8. 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>

이제 element 지시어 대신 열 이름에 xml 지시어인 Summary!2!SummaryDescription!xml을 지정하면 엔터티화 없이 요약 설명을 받게 됩니다.

<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

9. 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>

10. xmltext 지시어 지정

이 예에서는 EXPLICIT 모드를 사용하는 SELECT 문에서 xmltext 지시어를 사용하여 오버플로 열의 데이터 주소를 지정하는 방법을 보여 줍니다.

Person 테이블을 검토해 보면 이 테이블에는 XML 문서 중 사용되지 않은 부분을 저장하는 Overflow 열이 있는 것을 볼 수 있습니다.

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은 지정되어 있지 않지만 범용 테이블 열 이름을 제공하는 중에 directivexmltext로 설정됩니다.

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 문서에서 다음에 유의하십시오.

  • AttributeNameOverflow 열에 대해 지정되어 있지 않고 xmltext 지시어가 지정되어 있기 때문에 <overflow> 요소의 특성이 묶는 <Parent> 요소의 특성 목록에 첨부됩니다.
  • <xmltext> 요소의 PersonID 특성은 동일 요소 수준에서 검색된 PersonID 특성과 충돌하기 때문에 <xmltext> 요소의 특성은 PersonID가 NULL인 경우에도 무시됩니다. 특성은 일반적으로 오버플로의 동일한 이름의 특성에 우선합니다.

다음은 결과입니다.

<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> 요소의 하위 요소로 추가됩니다.

예를 들어 Overflow 열에 하위 요소가 있게 되도록 Person 테이블의 데이터를 변경합니다.

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>

AttributeNamexmltext 지시어와 함께 지정된 경우 <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>

이 쿼리 요소에서는 directivePersonName 특성에 대해 지정됩니다. 그 결과 PersonName이 묶는 <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 파서는 결과 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 지원 받기