CDATA с дочерними элементами - PullRequest
1 голос
/ 03 февраля 2020

Я хотел бы получить результат с подмножеством MakeType. Прямо сейчас я получаю весь блок, а не элементы MakeType. Когда XML разрешает тип, теги Series и class должны быть созданы для них. Это на SQL Server Standard 2017. И я действительно не знаю стиль 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');

Результат должен выглядеть следующим образом Когда код видит, что MakeType должен иметь Series и класс ниже, как дочерний элемент. Это желаемый вывод 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>  

Ответы [ 2 ]

0 голосов
/ 04 февраля 2020

Для сравнения я хотел бы показать, насколько легко реализовать раздел CDATA, когда механизм XQuery полностью поддерживает стандарты. Ниже приведена реализация BaseX 9.3.1, в которой используется cdata-section-elements параметр сериализации: Список элементов, которые будут выводиться в виде 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>

Вывод

<?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>
0 голосов
/ 04 февраля 2020

Я изо всех сил пытался произвести то, что вам нужно, используя FOR XML EXPLICIT. В конце концов я вернулся к использованию выражения XQuery FLWOR . Помните, что SQL Сервер XML тип данных не может содержать CDATA разделы. Вам необходимо использовать тип данных NVARCHAR(MAX). Проверьте это здесь: Как использовать CDATA в SQL XML

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];

Вывод

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