web-dev-qa-db-ja.com

SQLXMLでCDATAを使用する方法

誰かがXML出力テンプレートを手伝ってくれませんか。クライアントからxml出力ファイルの作成を依頼されました。このファイルは、クライアントのCRMにフィードされます。そのため、クライアントが要求したテンプレートと完全に一致する必要があります。いくつかのフィールドでCDATAとは別に、完全に一致させることができました。

以下は、テスト目的で使用できるクエリです。 ClientフィールドとAreaフィールドにCDATAラップが必要です。以下のコードを実行して取得した出力も添付しました

            If OBJECT_ID('tempdb..#Temp') is Not NULL
            Drop table #Temp

            CREATE TABLE #Temp
            (
                [ShiftDate] [date] NULL,
                [Ref_Num] [varchar](20) NULL,
                [Agency_Worker_Name] [varchar](100) NULL,
                [Client] [varchar](100) NULL,
                [Area] [VarChar] (100) Null,
                [Assignment] [varchar](20) NULL,
                [Contract_Start] [varchar](30) NULL,
                [Contract_End] [varchar](30) NULL,
                [Contract_BreakInMinutes] [varchar](10) NULL,
                [Contract_Total] [varchar](30) NULL,
                [Actual_Start] [varchar](30) NULL,
                [Actual_End] [varchar](30) NULL,
                [Actual_BreakInMinutes] [varchar](10) NULL,
                [Actual_Total] [varchar](30) NULL,
                [Commission] [decimal](18, 2) NULL,
                [Total_Cost] [decimal](18, 2) NULL,
                [Rate] [varchar](20) NULL,
                [OverallCost] [decimal](18, 2) NULL,
                [AgencybackingReport] [int] NULL,
                [AccountCode] [varchar](20) NULL
            )

            Insert Into #Temp
            Values 
            ('2018-07-24',
             '83076641',
             'ABCD',
             'ABCD',
             'ABCD',
             'CPA00',
             '09:00',
             '17:00',
             '30',
             '07:30',
             '10:30',
             '17:00',
             '30',
             '05:30',
             '28.49',
             '159.01',
             'Basic',
             '221.59',
             '1220883',
            ' ABCD')



            Declare @xml Int=(Select max(AgencyBackingReport)  From #Temp)

            select @xml As [@AgencyBackingReport],(Select 
            [Ref_Num] As [@reference],
            [ShiftDate] as [@startdate],
            Case When [AccountCode] is NULL Then 'Unknown' Else [AccountCode] End as [@accountcode],
            Contract_Start As 'PlannedShift/Start',
            Contract_End As 'PlannedShift/End',
            Contract_BreakInMinutes As 'PlannedShift/BreakinMinutes',
            Actual_Start As 'ActualShift/Start',
            Actual_End As 'ActualShift/End',
            Actual_BreakInMinutes As 'ActualShift/BreakinMinutes',
            OverallCost As [OverallCost],
            Agency_Worker_Name As 'AdditionalInformation/WorkerName',
            Client  As 'AdditionalInformation/Client',
            Area As 'AdditionalInformation/Area',
            -- ( select 
            --         1 as Tag ,
            --        0 as Parent ,
            --            (Select 
            --         Area 
            --        From #Temp M2
            --   Where M1.Ref_Num = m2.Ref_Num)
            --   As [Area!1!!CDATA]
            --   for xml explicit 
            --)   As 'AdditionalInformation/Area',
            Assignment As 'AdditionalInformation/Assignment',
            Commission As 'AdditionalInformation/Commission',
            Total_Cost As 'AdditionalInformation/TotalCost',
            Rate As 'AdditionalInformation/Rate'
            From #Temp M1
            for xml path('Shift'),Type)
            for XML Path('Shifts'),Type

enter image description here

11
user3482527

CDATAがかなり時代遅れであることをご存知のようです...これについて何かを読みたい場合は、 このリンク とこの回答のリンクをたどることができます。

時々私たちはそれに固執しなければなりません...特に不十分に行われたサードパーティのツールがそれを要求する場合。しかしながら...

CDATAセクションを含める唯一の方法は、_FOR XML EXPLICIT_を使用することですが、これはかなり不器用です。

注意しなければならない問題の1つは、これをXMLタイプで格納できないことです。

CDATAセクションを含むXMLを文字列型からネイティブXMLに変換するたびに、CDATAは失われ、適切にエスケープされた通常のtext()ノードになります。

これを試して

_DECLARE @tbl TABLE(XmlAsString NVARCHAR(MAX), NativeXml XML);
INSERT INTO @tbl 
SELECT (
        SELECT 1      AS Tag
              ,NULL   AS Parent
              ,'test <&>' AS [SomeNode!1!!cdata]
        FOR XML EXPLICIT
        )
       ,(
        SELECT 1      AS Tag
              ,NULL   AS Parent
              ,'test <&>' AS [SomeNode!1!!cdata]
        FOR XML EXPLICIT
        );

SELECT * FROM @tbl
_

結果

_<SomeNode><![CDATA[test <&>]]></SomeNode>   
<SomeNode>test &lt;&amp;&gt;</SomeNode>
_

つまり、CDATAセクションを保持すると、文字列型のままになります。大きな欠点かもしれません...

問題に戻る

私がこれを正しく見れば、あなたは上記のようなすべてを手に入れたいのですが

_<Area><![CDATA[ABCD]]></Area>
_

... の代わりに

_<Area>ABCD</Area>
_

アプローチ1(醜い):

上記のようにXMLを作成してから、read_<Area>_のコンテンツを作成し、文字列レベルでREPLACEを使用してこのノードを完全に変更します。しかし、これをXMLに戻してはいけません...

アプローチ2(不器用):

これはCDATAセクションのあるXMLであり、完全ではありませんが、原則は次のとおりです。

_SELECT   1          AS Tag
        ,NULL       AS Parent
        ,1220883    AS [Shifts!1!AgencyBackingReport]
        ,NULL       AS [Shift!2!reference]
        ,NULL       AS [Shift!2!startdate]
        ,NULL       AS [Shift!2!accountcode]
        ,NULL       AS [PlannedShift!3!Start!Element]
        ,NULL       AS [PlannedShift!3!End!Element]
        ,NULL       AS [PlannedShift!3!BreakingMinutes!Element]
        ,NULL       AS [ActualShift!4!dummy!Element] --just a dummy
        ,NULL       AS [OverallCost!5]
        ,NULL       AS [AdditionalInformation!6!WorkerName!Element]
        ,NULL       AS [AdditionalInformation!6!Area!CDATA]
        ,NULL       AS [AdditionalInformation!6!Assignment!Element]
UNION ALL
SELECT 2
      ,1
      ,NULL
      ,83076641
      ,'2018-07-24'
      ,'ABCD'
      ,NULL
      ,NULL
      ,NULL
      ,NULL
      ,NULL
      ,NULL
      ,NULL
      ,NULL
UNION ALL
SELECT 3
      ,2
      ,NULL
      ,NULL
      ,NULL
      ,NULL
      ,'09:00'
      ,'17:00'
      ,30
      ,NULL
      ,NULL
      ,NULL
      ,NULL
      ,NULL
UNION ALL
SELECT 4 --just a dummy
      ,2
      ,NULL
      ,NULL
      ,NULL
      ,NULL
      ,NULL
      ,NULL
      ,NULL
      ,'dummy'
      ,NULL
      ,NULL
      ,NULL
      ,NULL
UNION ALL
SELECT 5 
      ,2
      ,NULL
      ,NULL
      ,NULL
      ,NULL
      ,NULL
      ,NULL
      ,NULL
      ,NULL
      ,211.59
      ,NULL
      ,NULL
      ,NULL
UNION ALL
SELECT 6
      ,2
      ,NULL
      ,NULL
      ,NULL
      ,NULL
      ,NULL
      ,NULL
      ,NULL
      ,NULL
      ,NULL
      ,'ABCD'
      ,'ABCD'
      ,'CPA00'
FOR XML EXPLICIT
_

結果

_<Shifts AgencyBackingReport="1220883">
  <Shift reference="83076641" startdate="2018-07-24" accountcode="ABCD">
    <PlannedShift>
      <Start>09:00</Start>
      <End>17:00</End>
      <BreakingMinutes>30</BreakingMinutes>
    </PlannedShift>
    <ActualShift>
      <dummy>dummy</dummy>
    </ActualShift>
    <OverallCost>211.59</OverallCost>
    <AdditionalInformation>
      <WorkerName>ABCD</WorkerName>
      <Area><![CDATA[ABCD]]></Area>
      <Assignment>CPA00</Assignment>
    </AdditionalInformation>
  </Shift>
</Shifts>
_
3
Shnugo

クエリでFORXMLを使用します。

E.g: select * from table1 FOR XML AUTO

このようなステートメント(悪名高いに基づく):

SELECT 
   CustomerID as "@CustomerID",
   CompanyName,
   Address as "address/street",
   City as "address/city",
   Region as "address/region",
   PostalCode as "address/Zip",
   Country as "address/country",
   ContactName as "contact/name",
   ContactTitle as "contact/title",
   Phone as "contact/phone", 
   Fax as "contact/fax"
FROM Customers
FOR XML PATH('Customer')
1
Tanmay Nehete