带有CDATA块的SQL Server XML数据

时间:2018-01-10 14:21:02

标签: sql-server xml xpath

我将XML有效内容存储在SQL Server表中,该表的数据类型为“XML”。我收到的数据有一个包含在CDATA块中的部分。这是一个例子:

<event>
  <projectId>123456</projectId>
  <eventTs>2018-01-04T13:07:23</eventTs>
  <eventData>
    <![CDATA[
    <company>
      <companyId>849</companyId>
      <companyName>My Company Name</companyName>
      <activeFlag>Y</activeFlag>
      <timestamp>27-JUL-17</timestamp>
    </company>
    ]]>
  </eventData>
</event>

当这个数据落入我的表中,数据类型为“XML”的字段时,“CDATA”块被剥离,但随后所有的“&lt;”和“&gt;”字符被转义。由于这些字符是转义的,因此对该数据字段的XPATH查询不再起作用。除了必须在插入/转换为XML数据类型之前去掉CDATA块之外,还有什么方法可以解决这个问题吗?

这是插入XML数据类型字段后的数据:

<event>
    <projectId>123456</projectId>
    <eventTs>2018-01-04T13:07:23</eventTs>
    <eventData>
&lt;company&gt;
          &lt;companyId&gt;849&lt;/companyId&gt;
&lt;companyName&gt;My Company Name&lt;/companyName&gt;
&lt;activeFlag&gt;Y&lt;/activeFlag&gt;
&lt;timestamp&gt;27-JUL-17&lt;/timestamp&gt;
&lt;/company&gt;
</eventData>
</event>

1 个答案:

答案 0 :(得分:0)

存储在 CDATA部分中是一种非常糟糕的方法。这个区块内的所有内容都只是文字。此特殊文本看起来像XML,但您无法查询此XML以返回<companyName>

试试这个:

DECLARE @xml XML=
N'<event>
  <projectId>123456</projectId>
  <eventTs>2018-01-04T13:07:23</eventTs>
  <eventData>
    <![CDATA[
    <company>
      <companyId>849</companyId>
      <companyName>My Company Name</companyName>
      <activeFlag>Y</activeFlag>
      <timestamp>27-JUL-17</timestamp>
    </company>
    ]]>
  </eventData>
</event>';

SQL Server的开发人员决定不再支持CDATA了。它将被隐含地带走,而其内容仍然被妥善转义。但是你可以毫无问题地阅读内容:

SELECT @xml.value('(/event/eventData)[1]','nvarchar(max)');  

关键是:这个结果看起来像一个XML,但是 - 为了使用它就像一个XML - 它必须被铸造。

这可以解决这个问题:

DECLARE @innerXML XML=(SELECT CAST('<eventData>' + @xml.value('(/event/eventData)[1]','nvarchar(max)') + '</eventData>' AS XML));
SET @xml.modify('delete /event/eventData[1]');
SET @xml.modify('insert sql:variable("@innerXML") as last into /event[1]');
SELECT @xml;

轻松:

只要传入的XML是一个字符串(在您尝试将其转换为XML之前),您就可以丢弃CDATA标记:

DECLARE @xmlString NVARCHAR(MAX)=
N'<event>
  <projectId>123456</projectId>
  <eventTs>2018-01-04T13:07:23</eventTs>
  <eventData>
    <![CDATA[
    <company>
      <companyId>849</companyId>
      <companyName>My Company Name</companyName>
      <activeFlag>Y</activeFlag>
      <timestamp>27-JUL-17</timestamp>
    </company>
    ]]>
  </eventData>
</event>';

SELECT CAST(REPLACE(REPLACE(@xmlString,' <![CDATA[',''),']]>','') AS XML)