2016-08-19 69 views
0

这是我的xml。我的目标是使用CDATA将数据封装在Value节点中,然后将其导入到移除了CDATA的Xml类型列中。围绕XML包装和删除CDATA

<Custom> 
    <Table>Shape</Table> 
    <Column>CustomScreen</Column> 
    <Value>Data</Value> 
<Custom> 

现在我从表中的XML,然后我相信我把CData的围绕它来取代值节点内的“数据”,其中ShapeInfo是XML类型和CustomPanel是第一个节点[ShapeInfo ] XML。

SET @OutputXML= replace(@OutputXML, 'Data', CAST((SELECT [ShapeInfo]  
         FROM [Shape] WHERE [Shape_ID] = @ShapeID) as VARCHAR(MAX)) 

SET @OutputXML= replace(@OutputXML, '<CustomPanel', '<![CDATA[<CustomPanel') 

但是结果看起来是这样的,即使我预计它只有CDATA周围的信息:

<Value>&lt;CustomPanel VisibilityIndicator=""&gt;&lText="No" Checked="False" Height="20" Width="50"/&gt;&lt;/Cell&gt;&lt;/Row&gt;&lt;/Table&gt;&lt;/CustomPanel&gt;</Value> 

那么我做了一些动态SQL来更新列

EXEC('UPDATE ['+ @tableName + '] SET [' + @columnName + '] = ''' + @nodeValue + ''' WHERE Shape_ID = ''' + @ShapeID + '''') 

我被告知我可能能够使用以下来删除CDATA,但我没有使用它。

declare @x xml 
set @x=N'<Value>&lt;CustomPanel....... all the current info ...=&quot;&quot;&gt;</Value>' 

select @x.value('(/Value)[1]', 'nvarchar(max)') 

select '<![CDATA[' + @x.value('(/Value)[1]', 'nvarchar(max)') + ']]' 

再次检查列后,似乎它包含正确的信息。但是,我从来没有将它从VARCHAR改回XML,或者删除了CDATA符号,即使它们在我查看列时似乎已经消失了。那么我在这里错过了什么?这是一个正确的方法吗?

+0

Btw:这行'SET @ OutputXML = replace(@OutputXML,''。 – Shnugo

回答

2

如果你需要生成XML完全控制,你可以使用​​:

DECLARE @xml xml = '<Custom> 
    <Table>Shape</Table> 
    <Column>CustomScreen</Column> 
    <Value>Data</Value> 
</Custom>'; 

WITH rawValues AS 
(
    SELECT 
     n.value('Table[1]', 'nvarchar(20)') [Table], 
     n.value('Column[1]', 'nvarchar(20)') [Column], 
     n.value('Value[1]', 'nvarchar(20)') [Value] 
    FROM @xml.nodes('Custom') X(n) 
) 
SELECT 1 AS Tag, 
     NULL AS Parent, 
     [Table] AS [Custom!1!Table!ELEMENT], 
     [Column] AS [Custom!1!Column!ELEMENT], 
     [Value] AS [Custom!1!Value!CDATA] 
FROM rawValues 
FOR XML EXPLICIT 

它产生:

<Custom> 
    <Table>Shape</Table> 
    <Column>CustomScreen</Column> 
    <Value><![CDATA[Data]]></Value> 
</Custom> 

如果你需要扭转,替代源XML和使用ELEMENT代替CDATA

+0

我喜欢这个答案,来自我这边的+1,但是 - AFAIC--你应该考虑一下把CDATA变成XML。这在大多数情况下是不需要的...... – Shnugo

+0

尽管我试图按照你写的方式来完成字符串连接,但我终于做了字符串连接。 – DRockClimber

1

如果你真的需要你的XML中的CDATA部分,只有两个选项

  • 字符串连接(非常糟糕)
  • ​​(在这种情况下,你已经得到了从帕维尔的答案)

但是,您应该考虑到,CDATA部分仅适用于惰性输入。有绝对没有区别内容是否被封闭为CDATA节或正确逃脱。因此,微软决定甚至不支持现代XML方法中的CDATA语法。这仅仅是不需要的。

看看这些例子:

--I包含内容相同的字符串开始逃了出来,在CDATA

DECLARE @s VARCHAR(500)= 
'<root> 
<a>Normal Text</a> 
<a>Text with forbidden character &amp; &lt;&gt;</a> 
<a><![CDATA[Text with forbidden character & <>]]></a> 
</root>'; 

- 这串被强制转换为XML。

DECLARE @x XML=CAST(@s AS XML); 

- 这是输出,你可以看到,该CDATA部分更多编码的无CDATACDATA将始终有效的转义字符串替换:

SELECT @x; 

<root> 
    <a>Normal Text</a> 
    <a>Text with forbidden character &amp; &lt;&gt;</a> 
    <a>Text with forbidden character &amp; &lt;&gt;</a> 
</root> 

--The背铸清楚地表明,该XML内部没有任何CDATA

SELECT CAST(@x AS VARCHAR(500)); 

<root> 
    <a>Normal Text</a> 
    <a>Text with forbidden character &amp; &lt;&gt;</a> 
    <a>Text with forbidden character &amp; &lt;&gt;</a> 
</root> 

--Reading节点单接一个显示正确的内容呢

SELECT a.value('.','varchar(max)') 
FROM @x.nodes('/root/a') AS A(a) 

Normal Text 
Text with forbidden character & <> 
Text with forbidden character & <> 

的唯一原因使用CDATA和坚持,这必须被纳入XML文本重新演示文稿(这不是XML!)是第三方或遗留要求。

请注意:如果您使用字符串连接,则可以将XML以只读的CDATA存储为字符串格式。无论何时将其转换为XML,CDATA都将被忽略。使用​​允许类型安全的存储,但是对于更深的嵌套而言非常笨拙。这可能是与外部接口OK,但你应该(:-)由我)好好想一想这个...

两个链接到相关的答案:

+0

@Schnugo像往常一样好的信息。我结束了字符串连接。但我有个问题。在可能发生“sql注入”的情况下,CData是否有用?我被告知它会帮助人们插入随机的东西。 – DRockClimber