SQL SERVER xml with CDATA

﹥>﹥吖頭↗ 提交于 2019-12-18 09:49:46

问题


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?


回答1:


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;  



回答2:


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>


来源:https://stackoverflow.com/questions/38500858/sql-server-xml-with-cdata

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!