用 XML 输出替换 sql 中的文本
Posted
技术标签:
【中文标题】用 XML 输出替换 sql 中的文本【英文标题】:replace text inside sql with XML output 【发布时间】:2016-02-22 16:28:59 【问题描述】:我有这个问题:
SELECT [content_id]
,[content_html]
,[date_created]
,folder_id
FROM content ct
where folder_id=126
order by content_title
FOR XML PATH('PressRelease'), ROOT ('PressReleases')
当我运行这个查询时,这是生成的 XML 文件:
<PressReleases>
<PressRelease>
<content_id>6442452927</content_id>
<content_html><root><Date>2015-12-02</Date>
<Description><p class="customHeader">jobs to Philadelphia.</p>
<p>mtext in here.</p>
<p>mtext in here.</p>
</Description>
<SEO><h1>Pennsylvania Location</h1>
<div class="bulletRightBar"> The move was made possible in part by the Philadelphia Jobs
Credit</div>
</SEO>
</root></content_html>
<date_created>2015-12-02T09:47:12</date_created>
<folder_id>126</folder_id>
</PressRelease>
<PressReleases>
我需要的是这个 XML 文件:
<PressReleases>
<PressRelease>
<content_id>6442452927</content_id>
<content_html><root><Date>2015-12-02</Date>
<Description><p class="customHeader">jobs to Philadelphia.</p>
<p>mtext in here.</p>
<p>mtext in here.</p>
</Description>
<SEO><h1>Pennsylvania Location</h1>
<div class="bulletRightBar"> The move was made possible in part by the Philadelphia Jobs
Credit</div>
</SEO>
</root></content_html>
<date_created>2015-12-02T09:47:12</date_created>
<folder_id>126</folder_id>
</PressRelease>
<PressReleases>
在<content_html>
中,我想将<root>
<date>
和<Description>
设为XML 元素,但将其余部分保留为编码的html。
这是sql结果的截图
【问题讨论】:
请说明更多细节:“content_html”的数据类型,该列中的数据在您将其放入XML 之前如何?能否请您设置一个SQL Fiddle 或过去一些真实的样本数据? @Shnugo 我为 sql 结果添加了一个 SC 看来你是在自找麻烦:) @JoePhilllips 为什么会这样? 您想将</Description>
和<SEO>
保留为编码的HTML 还是将它们也进行转换
【参考方案1】:
这并不漂亮,但您可以将 XML 字段转换为字符串,使用 REPLACE 函数并将其转换回 XML,如下所示。您可能想要创建一个函数来执行此操作,因为该行会进行大量替换:
SELECT [content_id]
,cast(REPLACE(cast([content_html] as varchar(max)),'<root>','<root>') as xml)
,[date_created]
,folder_id
FROM content ct
where folder_id=126
order by content_title
FOR XML PATH('PressRelease'), ROOT ('PressReleases')
或者这里是用函数调用它的方法
CREATE FUNCTION [dbo].[XML_Replace]
(@XML_Field XML)
RETURNS XML
BEGIN
DECLARE @xml varchar(max)
DECLARE @xml_Mid varchar(max)
DECLARE @strtBigInt bigint
, @endBigInt bigint
SET @xml = cast(@XML_Field as varchar(max))
SET @strtBigInt = CHARINDEX('<Description>',@xml)
SET @endBigInt = CHARINDEX('</SEO>',@xml)
SET @xml_Mid = SUBSTRING(@xml, @strtBigInt+19,@endBigInt-@strtBigInt-19);
RETURN(cast(REPLACE(REPLACE(REPLACE(REPLACE(substring(@xml,0,@strtBigInt+19),'<','<'),'>','>') + @xml_Mid + REPLACE(REPLACE(substring(@xml,@endBigInt,Len(@xml)),'<','<'),'>','>'),'</Description>','</Description>'),'<SEO>','<SEO>') as xml));
END
然后在你的代码中使用函数:
SELECT [content_id]
,dbo.XML_Replace([content_html]) as content_html
,[date_created]
,folder_id
FROM content ct
where folder_id=126
order by content_title
FOR XML PATH('PressRelease'), ROOT ('PressReleases')
【讨论】:
第一种方法,您必须用正确的 XML 标记替换每个单独的标记。我刚刚添加的函数会查找开始和结束的描述标签,并分别更新它们之前和之后的所有<
和 >
如果您不希望您的 SEO 更新为 XML 标签,您只需要稍微编辑函数以供 @endBigInt
查找 SEO 结束标签,然后单独替换将&lt;/Description&gt;
替换为</Description>
的@xml_Mid
字符串
该功能对您不起作用?你所期望的输出有什么问题?
它将为我解码的所有内容转换为节点,这不是我想要的......有一些我不想编码的 html 标签
'XML_Replace' is not a recognized built-in function name.
【参考方案2】:
看起来[content_html]
存储为字符串(可能是nvarchar
?)。它的内容看起来像一个格式良好的 XML。如果是这种情况,可以将CAST
转换为 XML 以正确合并到结果集中:
-- Test Data Set
WITH content AS (
SELECT
6442452927 AS [content_id],
N'<root><Date>2015-12-02</Date>
<Description><p class="customHeader">jobs to Philadelphia.</p>
<p>mtext in here.</p>
<p>mtext in here.</p>
</Description>
<SEO><h1>Pennsylvania Location</h1>
<div class="bulletRightBar"> The move was made possible in part by the Philadelphia Jobs
Credit</div>
</SEO>
</root>' AS [content_html],
CAST('2015-12-02T09:47:12' AS DATETIME2) AS [date_created],
126 AS [folder_id],
1 AS [content_title]
)
-- Query
SELECT [content_id]
,CAST((Select
CAST([content_html] AS XML).query('/root/Date/node()') AS [Date]
,CAST(CAST([content_html] AS XML).query('/root/Description/node()') AS nvarchar(max)) As [Description]
,CAST(CAST([content_html] AS XML).query('/root/SEO/node()') AS nvarchar(max)) AS [SEO]
FOR XML PATH('root'), ROOT ('content_html')) As XML)
,[date_created]
,[folder_id]
FROM content ct
WHERE folder_id=126
ORDER BY content_title
FOR XML PATH('PressRelease'), ROOT ('PressReleases')
【讨论】:
这会将我的查询中的所有内容解码为 HTML 标记 (),这不是我想要的 @Alundrathedreamwalker 这可以通过更多CAST
s 来修复。【参考方案3】:
这方面的棘手之处在于您的content_html
字段既不包含XML 也不包含HTML。这是一种非常奇怪的数据编码方式。如果可能,您可能希望将字段中的数据转换为 XML,这将使查询变得非常容易。例如,您可以将您提供的数据中的字段转换为:
<root>
<Date>2015-12-02</Date>
<Description><p class="customHeader">jobs to Philadelphia.</p>
<p>mtext in here.</p>
<p>mtext in here.</p>
</Description>
<SEO><h1>Pennsylvania Location</h1>
<div class="bulletRightBar"> The move was made possible in part by the Philadelphia Jobs
Credit</div>
</SEO>
</root>
如果您无法更改数据的存储方式,一种方法是使用下面的代码来回进行一些转换。子查询创建一个名为[content_xml]
的字段,它将content_html
字段中的数据转换为XML 数据类型。这假定您的所有数据都可以转换为有效的 XML。然后对于 XML 中 root
下的每个节点,它会重建节点并使用 CDATA 包装数据,以便保留所需的格式。
--set up test data
create table #content
([content_id] bigint
,[content_html] varchar(max)
,[date_created] datetime
,folder_id int
, content_title varchar(50)
)
insert into #content
values (
6442452927,
'<root><Date>2015-12-02</Date>
<Description><p class="customHeader">jobs to Philadelphia.</p>
<p>mtext in here.</p>
<p>mtext in here.</p>
</Description>
<SEO><h1>Pennsylvania Location</h1>
<div class="bulletRightBar"> The move was made possible in part by the Philadelphia Jobs
Credit</div>
</SEO>
</root>',
'2015-12-02T09:47:12',
126,
'Content Title')
--Output
select [content_id],
(
SELECT
CONVERT(xml,
'<' + convert(varchar(max),T.c.query('local-name(.)')) + '>'
+ (select convert(xml, '<![CDATA[' + convert(varchar(max),T.c.query('node()')) + ']]>') for xml path(''))
+ '</' + convert(varchar(max),T.c.query('local-name(.)')) + '>'
)
FROM content_xml.nodes('/root/*') T(c)
for xml path(''), type
) as [content_html/root]
,[date_created]
,folder_id
from
(
SELECT *,
convert(xml,convert(xml,content_html).value('.','varchar(max)')) [content_xml]
FROM #content ct
) AllData
order by content_title
FOR XML PATH('PressRelease'), ROOT ('PressReleases')
【讨论】:
这对你有用吗?它可以满足您在测试用例中所说的需要。【参考方案4】:请试试这个
SELECT [content_id]
,CONVERT(XML,REPLACE(REPLACE([content_html],'<','<'),'>','>')) AS [content_html]
,[date_created]
,folder_id
FROM content ct
WHERE folder_id=126
ORDER BY content_title
FOR XML PATH('PressRelease'), ROOT ('PressReleases')
【讨论】:
以上是关于用 XML 输出替换 sql 中的文本的主要内容,如果未能解决你的问题,请参考以下文章