SQL SERVER xml with CDATA
Asked Answered
T

2

0

I have a table in my database with a column containing xml. The column type is nvarchar(max). The xml is formed in this way

<root>
  <child>....</child>
  .
  .
  <special>
   <event><![CDATA[text->text]]></event>
   <event><![CDATA[text->text]]></event>
  ...
  </special>
</root>

I have not created the db, I cannot change the way information is stored in it but I can retrieve it with a select. For the extraction I use select cast(replace(xml,'utf-8','utf-16')as xml) from table

It works well except for cdata, whose content in the query output is: text -> text

Is there a way to retrieve also the CDATA tags?

Tahsildar answered 21/7, 2016 at 9:53 Comment(1)
Hi, I am not having time to test the given solution, I'll update the question asap. If youhave alternative solution, I ma happy to test itTahsildar
C
2

Well, this is - as far as I know - not possible on normal ways...

The CDATA section has one sole reason: include invalid characters within XML for lazy people...

CDATA is not seen as needed at all and therefore is not really supported by normal XML methods. Or in other words: It is supported in the way, that the content is properly escaped. There is no difference between correctly escaped content and not-escaped content within CDATA actually! (Okay, there are some minor differences like including ]]> within a CDATA-section and some more tiny specialties...)

The big question is: Why?

What are you trying to do with this afterwards?

Try this. the included text is given as is:

DECLARE @xml XML = 
'<root>
  <special>
   <event><![CDATA[text->text]]></event>
   <event><![CDATA[text->text]]></event>
  </special>
</root>'

SELECT t.c.query('text()')
FROM @xml.nodes('/root/special/event') t(c);

So: Please explain some more details: What do you really want?

If your really need nothing more than the wrapping CDATA you might use this:

SELECT '<![CDATA[' + t.c.value('.','varchar(max)') + ']]>'
FROM @xml.nodes('/root/special/event') t(c);

Update: Same with outdated FROM OPENXML

I just tried how the outdated approach with FROM OPENXML handles this and found, that there is absolutely no indication in the resultset, that the given text was within a CDATA section originally. The "Some value here" is exactly returned in the same way as the text within CDATA:

DECLARE @doc XML = 
'<root>
  <child>Some value here </child>
  <special>
   <event><![CDATA[text->text]]></event>
   <event><![CDATA[text->text]]></event>
  </special>
</root>';

DECLARE @hnd INT;

EXEC sp_xml_preparedocument @hnd OUTPUT, @doc;  

SELECT * FROM OPENXML (@hnd, '/root',0);

EXEC sp_xml_removedocument @hnd;  
Cutch answered 24/7, 2016 at 0:14 Comment(0)
W
1

This is how to include cdata on child nodes in XML, using pure SQL. But; it's not ideal.

SELECT 1 AS tag, 
   null AS parent, 
   '10001' AS 'Customer!1!Customer_ID!Element', 
   'AirBallon Captain' AS 'Customer!1!Title!cdata', 

   'Customer!1' = (
        SELECT 
               2 AS tag, 
               NULL AS parent, 
               'Wrapped in cdata, using explicit' AS 'Location!2!Title!cdata' 
               FOR XML EXPLICIT)

FOR XML EXPLICIT, ROOT('Customers')

CDATA is included, but Child element is encoded using

&gt;

instead of > Which is so weird from a sensable point of view. I'm sure there are technical explanations, but they are stupid, because there is no difference in the FOR XML specification.

You could include the option type on the inner child node and then loose cdata too.. BUT WHY OH WHY?!?!?!?! would you (Microsoft) remove cdata, when I just added it?

<Customers>
  <Customer>
    <Customer_ID>10001</Customer_ID>
    <Title><![CDATA[AirBallon Captain]]></Title>
     &lt;Location&gt;
       &lt;Title&gt;&lt;![CDATA[wrapped in cdata, using explicit]]&gt;&lt;/Title&gt;
     &lt;/Location&gt;
 </Customer>
</Customers>
Wakerife answered 8/8, 2019 at 10:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.