HTML 解析器在 SQL SERVER 2005 中(基于集合的方法)






4.50/5 (8投票s)
一个用于仅解析 HTML 正文内容的 HTML 解析器。
引言
虽然在日常编程中不常用,但有时我们需要解析 HTML 文本以提取数据。最近,我遇到了同样的需求,因此想与大家分享。
背景
最近我的一个同事遇到了一个问题。他的需求是从某个 HTML 文本中提取相关文本。在 Google 上搜索后,我找到了一些答案 SQL SERVER – 2005 – UDF – 用户定义函数以去除 HTML – 解析 HTML – 不使用正则表达式,但这些无法满足他的需求。因此,我为他创建了一个。同时,他还面临另一个挑战。HTML 文本可以是任何内容,例如,它可以包含 JavaScript 函数、样式标签等。此外,它可能嵌入在 BODY
标签内,或者可能根本没有 BODY
标签。无论哪种情况,只需要解析 body 标签内的部分。
例如:
输入(A)
<html><head><title></title><body><a href="#">从这里提取文本</a></body></html>
输入(B)
<a href="#">从这里提取文本</a>
输出: 从这里提取文本
程序 / Sql 查询
--Variable Declarations
DECLARE @OriginalStr VARCHAR(MAX)
DECLARE @NewStr VARCHAR(MAX)
DECLARE @StartIndex INT
DECLARE @EndIndex INT
DECLARE @Noise TABLE(Noise VARCHAR(100),ReplaceChars VARCHAR(10))
--End of Declaration
--Variable initialisation
--SET @OriginalStr = 'Niladri Biswas at www.codeproject.com.
An example of parsing html at codeproject.com' -- original data
SET @OriginalStr = '
Click the button <input type="button" value="some button" onclick="test();">
hello world
I am followed by a BLANK SPACE and then a terminator
It''s a new line
Fonts are nice features
Nice link......
www.codeproject.com
'
INSERT INTO @Noise(Noise,ReplaceChars)
SELECT ' ',space(1) UNION ALL SELECT '>',space(1) UNION ALL
SELECT '<',space(1) UNION ALL SELECT '
',space(2) UNION ALL
SELECT ' ',space(2)
-- End of initialisation
--Step 1: Extract text between and
SELECT @StartIndex= CHARINDEX('', @OriginalStr)
SELECT @EndIndex= CHARINDEX('',@OriginalStr)
SELECT @OriginalStr =
CASE WHEN(@StartIndex = 0 or @EndIndex = 0) THEN @OriginalStr
ELSE
SUBSTRING(@OriginalStr,@StartIndex ,_
((@EndIndex - @StartIndex) + 7 )) END-- Adding 7 since length of = 7
--Step 2: Extract the relevant text between the tags
--Generate a number table
;WITH Num_Cte AS
(
SELECT 1 AS rn
UNION ALL
SELECT rn +1 AS rn
FROM Num_Cte
WHERE rn <= LEN(@OriginalStr)
)
-- Shred into individual characters
, Get_Individual_Chars_Cte AS
(
SELECT
rn AS Id
,chars
FROM Num_Cte
CROSS APPLY( SELECT SUBSTRING(@OriginalStr,rn,1) AS chars) SplittedChars
)
--Combine the characters again to obtain the extracted text between the tags
SELECT @NewStr = ExtractedText FROM (
SELECT CAST(chars AS VARCHAR(MAX)) FROM (
--Get the characters between the tags
SELECT a.* FROM Get_Individual_Chars_Cte a
INNER JOIN
(
--Find the position of the characters between the tags
SELECT rn FROM Num_Cte EXCEPT
(SELECT n.rn
FROM Num_Cte n
JOIN(
-- Find the start and end range of characters
-- between < and > for all tags
SELECT
Id AS StartRange
,(SELECT TOP 1 Id
FROM Get_Individual_Chars_Cte
WHERE Id > a.Id
AND chars='>'
ORDER BY Id) AS EndRange
FROM Get_Individual_Chars_Cte a
WHERE chars='<')X(StartRange,EndRange)
ON n.rn BETWEEN X.StartRange AND X.EndRange)
)X(rn)
ON a.Id = X.rn
)X(id,chars)
FOR XML PATH('')
)X(ExtractedText)
OPTION(MAXRECURSION 0)
--Remove the noises
SELECT @NewStr = REPLACE(@NewStr, Noise, ReplaceChars) FROM @Noise
SELECT ParsedText = @NewStr
输出
ParsedText
点击按钮 hello world 我后面跟着一个空格,然后是一个终止符。这是一个新行。字体是很好的特性。不错的链接...... www.codeproject.com
解释
首先,我们需要检查给定的 HTML 是否包含 body 标签,这将作为输入源。
之后,下一步是提取相关的文本。
为了完成这个任务,我们将使用一个在运行时使用递归 CTE 创建的数字表。
接下来,将数据拆分为单个字符。例如:CROSS APPLY( SELECT SUBSTRING(@OriginalStr,rn,1) AS chars) SplittedChars。
下一步是找到所有标签之间的 < 和 > 之间的字符的起始和结束范围。
完成这项任务后,下一步是找到标签之间的字符位置,并再次组合字符(使用 FOR XML PATH(''))以获得标签之间的提取文本。
组合字符后,我们会遇到一些垃圾字符,例如 ' ','>' 等。
因此,我们将保留一个噪声表,其中噪声(让我们称之为垃圾字符)将被一个空格替换。完成后,我们将实现我们的目标。
关注点
这篇文章展示了一种使用基于集合的方法解析数据的方法。它还展示了我们如何在单个 Replace 语句中替换数据,而不是多个语句。正如本文所证明的那样,FOR XML PATH 在组合字符方面非常方便。
历史
- 2010 年 1 月 12 日:初始发布