带有子元素的 CDATA

CDATA with Child elements

我想要带有 MakeType 子集的结果。 现在我得到了整个块而不是 MakeType 的元素。 当 XML 解析类型、系列和 class 标签时,应该为它们创建一个元素。这是 SQL 服务器标准 2017.And 我真的不知道 CDATA xml 风格,不会使用它,但供应商需要 CDATA 类型。

       ---Create Temp Table         
            declare @RepCar table
            (
            [Name] varchar(10),
            [Make] varchar(10),
            [Model] varchar(10),
            [Price]  money,
            [Type] varchar(10),
            [Series]  varchar(10),
            [Class] Varchar(10)
            );
             insert into @RepCar
            (
            Name, Make, Model, Price, Type, Series, Class
            )
            values
            ('Car1', 'Make1', 'Model1', 100, 'Type1', 'IS', 'Sedan'),
            ('Car1', 'Make1', 'Model1', 100, 'Type1', 'LS' , 'Sport'),
            ('Car2', 'Make2', 'Model2', 200, 'Type2', 'M3' , 'Sport'),
            ('Car3', 'Make3', 'Model3', 300, 'Type3','GS350','Sedan');




           --Declare Variables   
            DECLARE @TransactionId NVARCHAR(100)
            DECLARE @TransactionDateTime DATETIME
            --Setting Variable
            SET @TransactionId= (SELECT CONVERT(VARCHAR, CURRENT_TRANSACTION_ID()))
            SET @TransactionDateTime= GETDATE()

          --Create the XML

            select 1 AS Tag,
            0 AS Parent,
            'CollectSamplingData' as 'Message!1!TransactionType!cdata',
            @TransactionId as 'Message!1!TransactionID!cdata',
            @TransactionDateTime  as 'Message!1!TransactionDate!cdata',
            [Name]  as 'Message!1!CName!cdata',
            [Make]  as 'Message!1!MakeCar!cdata',
            [Model]  as 'Message!1!MakeModel!cdata',
            [Price]   as 'Message!1!DataValue!cdata',
            [Type]  as 'Message!1!MakeType!cdata' ,

         -----This is the SQL that is'nt working.
            ( select 
             1 AS Tag,
             0 AS Parent,
            [Series]  as 'Message!2!MakeSeries!cdata',
             [Class]  as 'Message!2!MakeClass!cdata' 
               from @RepCar  
             FOR XML EXPLICIT 
            )
            from @RepCar 
            FOR XML EXPLICIT, ROOT('Message');

结果应该看起来像 this.When 代码确实看到 MakeType 应该有 Series 和下面的 class 作为子元素。这些是所需的输出 XML

     <Message>
        <Message>
        <TransactionType><![CDATA[CollectSamplingData]]></TransactionType>
        <TransactionID><![CDATA[1482282230]]></TransactionID>
        <TransactionDate><![CDATA[2020-02-03T11:05:17.340]]></TransactionDate>
        <CName><![CDATA[Car1]]></CName>
        <MakeCar><![CDATA[Make1]]></MakeCar>
        <MakeModel><![CDATA[Model1]]></MakeModel>
        <DataValue><![CDATA[100.0000]]></DataValue>
        <MakeType><![CDATA[Type1]]>
                           <Series><![CDATA[IS]></Series>
                           <Class><![CDATA[Sedan]]></Class>
                           <Series><![CDATA[LS]></Series>
                           <Class><![CDATA[Sport]]></Class>
                           <Series><![CDATA[M3]></Series>
                           <Class><![CDATA[Sport]]></Class>
                           <Series><![CDATA[GS350]></Series>
                           <Class><![CDATA[Sedan]]></Class>>


            </MakeType>
       </Message>  

我努力通过使用 FOR XML EXPLICIT 来生产您需要的东西。最终,我恢复使用 XQuery FLWOR 表达式。请记住 SQL 服务器 XML 数据类型不能包含 CDATA 部分。您需要使用 NVARCHAR(MAX) 数据类型。在这里查看:如何在 SQL XML 中使用 CDATA

SQL

-- DDL and sample data population, start
DECLARE @RepCar TABLE
(
    [Name] VARCHAR(10),
    [Make] VARCHAR(10),
    [Model] VARCHAR(10),
    [Price] MONEY,
    [Type] VARCHAR(10),
    [Series] VARCHAR(10),
    [Class] VARCHAR(10)
);
INSERT INTO @RepCar
(
    Name,
    Make,
    Model,
    Price,
    Type,
    Series,
    Class
)
VALUES
('Car1', 'Make1', 'Model1', 100, 'Type1', 'IS', 'Sedan'),
('Car1', 'Make1', 'Model1', 100, 'Type1', 'LS', 'Sport'),
('Car2', 'Make2', 'Model2', 200, 'Type2', 'M3', 'Sport'),
('Car3', 'Make3', 'Model3', 300, 'Type3', 'GS350', 'Sedan');
-- DDL and sample data population, end

--Declare Variables   
DECLARE @TransactionId NVARCHAR(100) = CURRENT_TRANSACTION_ID();
DECLARE @TransactionDateTime DATETIME = GETDATE();

DECLARE @lt NCHAR(4) = '&lt;'
    , @gt NCHAR(4) = '&gt;';

SELECT REPLACE(REPLACE(TRY_CAST((SELECT 'CollectSamplingData' AS [TransactionType]
    , @TransactionId AS [TransactionID]
    , @TransactionDateTime AS [TransactionDate]
    , * 
FROM @RepCar
FOR XML PATH('r'), TYPE, ROOT('root')).query('<Messages><Message>
{
for $x in /root/r[1]
return (<TransactionType>{concat("<![CDATA[", data($x/TransactionType[1]), "]]>")}</TransactionType>,
        <TransactionID>{concat("<![CDATA[", data($x/TransactionID[1]), "]]>")}</TransactionID>,
        <TransactionDate>{concat("<![CDATA[", data($x/TransactionDate[1]), "]]>")}</TransactionDate>,
        <CName>{concat("<![CDATA[", data($x/Name[1]), "]]>")}</CName>,
        <MakeCar>{concat("<![CDATA[", data($x/Make[1]), "]]>")}</MakeCar>,
        <MakeModel>{concat("<![CDATA[", data($x/Model[1]), "]]>")}</MakeModel>,
        <DataValue>{concat("<![CDATA[", data($x/Price[1]), "]]>")}</DataValue>,
        <MakeType>{concat("<![CDATA[", data($x/Type[1]), "]]>")}
        {
            for $y in /root/r
            return (
                <Series>{concat("<![CDATA[", data($y/Series[1]), "]]>")}</Series>,
                <Class>{concat("<![CDATA[", data($y/Class[1]), "]]>")}</Class>
            )
        }
    </MakeType>)
}
</Message></Messages>') AS NVARCHAR(MAX)), @lt,'<'), @gt, '>') AS [XML with CDATA sections];

Output

<Messages>
    <Message>
        <TransactionType><![CDATA[CollectSamplingData]]></TransactionType>
        <TransactionID><![CDATA[1149709]]></TransactionID>
        <TransactionDate><![CDATA[2020-02-03T16:23:43.020]]></TransactionDate>
        <CName><![CDATA[Car1]]></CName>
        <MakeCar><![CDATA[Make1]]></MakeCar>
        <MakeModel><![CDATA[Model1]]></MakeModel>
        <DataValue><![CDATA[100.0000]]></DataValue>
        <MakeType><![CDATA[Type1]]>
            <Series><![CDATA[IS]]></Series>
            <Class><![CDATA[Sedan]]></Class>
            <Series><![CDATA[LS]]></Series>
            <Class><![CDATA[Sport]]></Class>
            <Series><![CDATA[M3]]></Series>
            <Class><![CDATA[Sport]]></Class>
            <Series><![CDATA[GS350]]></Series>
            <Class><![CDATA[Sedan]]></Class>
        </MakeType>
    </Message>
</Messages>

只是为了比较,我想展示一下当 XQuery 引擎完全支持标准时实现 CDATA 部分是多么容易。下面是使用 cdata-section-elements 序列化参数的 BaseX 9.3.1 实现:要作为 CDATA 输出的元素列表,由空格分隔.

两个元素 <city><motto> 以简单的声明方式作为 CDATA 部分发出。

XQuery

xquery version "3.1";
declare option output:omit-xml-declaration "no";
declare option output:cdata-section-elements "city motto";

declare context item := document {
<root>
  <row>
    <state>FL</state>
    <motto>In God We Trust</motto>
    <city>Miami</city>
  </row>    
  <row>
    <state>NJ</state>
    <motto>Liberty and Prosperity</motto>
    <city>Trenton</city>
  </row>
</root>
};

<root>
{
  for $r in ./root/row
  return $r
}
</root>

Output

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <row>
    <state>FL</state>
    <motto><![CDATA[In God We Trust]]></motto>
    <city><![CDATA[Miami]]></city>
  </row>
  <row>
    <state>NJ</state>
    <motto><![CDATA[Liberty and Prosperity]]></motto>
    <city><![CDATA[Trenton]]></city>
  </row>
</root>