从存储为nvarchar的xml中提取数据

时间:2016-06-16 14:26:16

标签: sql sql-server xml sql-server-2008 xml-parsing

我必须从存储为Subject的{​​{1}}中提取电子邮件XML

我正在使用此查询:

nvarchar

此查询的作用是首先提取包含电子邮件主题(SELECT rtrim((SELECT CAST( SUBSTRING( [XML] ,patindex('%<SUBJECT>%', [XML]) ,patindex('%</SUBJECT>%', [XML])-patindex('%<SUBJECT>%', [XML])+len('</SUBJECT>') ) as XML).value('(/SUBJECT/OPTION)[1]','nvarchar(2000)') FROM dbo.Mails )) as SUBJECT )的字符串,然后将其转换为XML,然后使用XML的<SUBJECT>....</SUBJECT>函数获取Subject值。

这很好用,但在某些情况下,XML格式不正确并且解析失败。示例:

value

这里的DECLARE @XMLData XML = '<SUBJECT> <OPTION CONSTRAINT="MASTER.IN_TITLE = '' OR MASTER.IN_LASTNAME = ''"><![CDATA[Découvrez nos offres de location]]> </OPTION> <OPTION CONSTRAINT="IN_TITLE <> '' AND MASTER.IN_LASTNAME <> ''"><![CDATA[~IN_TITLE~ ~IN_LASTNAME~, découvrez nos offres de location]]> </OPTION> </SUBJECT>' select rtrim((@XMLData).value('(/SUBJECT/OPTION)[1]','nvarchar(2000)') ) 属性Option我有一个特殊字符Constraint,如果我试图逃避这个字符,它会逃避所有其他字符,我丢失了XML结构。那怎么逃避呢?

另一个例子是:

<

我在DECLARE @XMLData XML = '<SUBJECT> <OPTION NAME="DEFAULT"><![CDATA[~(IF((IN_TITLE<>'' AND IN_LASTNAME<>''),IN_TITLE&' '&IN_LASTNAME&',',''))~ nos plus belles réalisations de 2015]]> </OPTION> </SUBJECT>' select rtrim((@XMLData).value('(/SUBJECT/OPTION)[1]','nvarchar(2000)') ) 附近收到错误,但我认为我们不需要在&IN_LASTNAME&中逃避特殊字符!

有没有人有解决方案来解析这些错误?

3 个答案:

答案 0 :(得分:2)

额外'&lt;'在'&lt;&gt;'中字符组合阻止了转换为XML。所以我建议你摆脱'&lt;&gt;'在将字符串转换为XML之前。在我的例子中,我用'!='替换它。我意识到这可能不适合你的情况,因为你需要处理来自可能有多行而不仅仅是变量的查询的结果,但希望这会给你一些想法。

DECLARE @badStringPos int

DECLARE @stringXMLData varchar(500)=  '<SUBJECT>
      <OPTION CONSTRAINT="MASTER.IN_TITLE = ''  OR  MASTER.IN_LASTNAME = ''"><![CDATA[Découvrez nos offres de location]]>
      </OPTION>
      <OPTION CONSTRAINT="IN_TITLE <> '' AND MASTER.IN_LASTNAME != ''"><![CDATA[~IN_TITLE~ ~IN_LASTNAME~, découvrez nos offres de location]]>
      </OPTION>
   </SUBJECT>'

declare @XMLData xml

set @badStringPos = patindex('%<>%', @stringXMLData)

while @badStringPos <> 0
begin
    set @stringXMLData = left(@stringXMLData, patindex('%<>%', @stringXMLData) - 1) + '!=' +
                         right(@stringXMLData, len(@stringXMLData) - (patindex('%<>%', @stringXMLData) + 1))
    set @badStringPos = patindex('%<>%', @stringXMLData)
end

set @XMLData = convert(xml, @stringXMLData)

select rtrim((@XMLData).value('(/SUBJECT/OPTION)[1]','nvarchar(2000)') )

一种选择是使用游标迭代查询结果。

答案 1 :(得分:2)

这些XML是如何生成的?这是你的控制吗?邪恶“&lt;,&gt;和&amp; ”的三个字符必须经过特殊处理,CDATA或转义。如果XML生成正确,无法将它们置于禁止的地方 ......

以下是两个工作示例。第二个与里斯琼斯相同...... 在第一个例子中,我替换了“&lt;&gt;”与&lt;&gt;

顺便说一下:当你正在处理其他特殊字符时,你应该用N'string'标记字符串,将其读作unicode

DECLARE @XMLData XML =  REPLACE(N'<SUBJECT>
      <OPTION CONSTRAINT="MASTER.IN_TITLE = ''  OR  MASTER.IN_LASTNAME = ''"><![CDATA[Découvrez nos offres de location]]>
      </OPTION>
      <OPTION CONSTRAINT="IN_TITLE <> '' AND MASTER.IN_LASTNAME <> ''"><![CDATA[~IN_TITLE~ ~IN_LASTNAME~, découvrez nos offres de location]]>
      </OPTION>
   </SUBJECT>','<>','&lt;&gt;');

select rtrim((@XMLData).value('(/SUBJECT/OPTION)[1]','nvarchar(2000)') );
GO

DECLARE @XMLData XML =  N'<SUBJECT>
      <OPTION NAME="DEFAULT"><![CDATA[~(IF((IN_TITLE<>'''' AND IN_LASTNAME<>''''),IN_TITLE&'' ''&IN_LASTNAME&'','',''''))~ nos plus belles réalisations de 2015]]>
      </OPTION>
   </SUBJECT>'

select rtrim((@XMLData).value('(/SUBJECT/OPTION)[1]','nvarchar(2000)') )

答案 2 :(得分:1)

我花了一些时间来弄清楚这里出了什么问题 - 你的字符串中有单引号(第二个例子),它们需要加倍;

DECLARE @XMLData XML =  '<SUBJECT>
      <OPTION NAME="DEFAULT"><![CDATA[~(IF((IN_TITLE<>'' AND IN_LASTNAME<>''),IN_TITLE&'' ''&IN_LASTNAME&'','',''))~ nos plus belles réalisations de 2015]]>
      </OPTION>
   </SUBJECT>'

select rtrim((@XMLData).value('(/SUBJECT/OPTION)[1]','nvarchar(2000)') )