65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.50/5 (8投票s)

2010年1月13日

CPOL

2分钟阅读

viewsIcon

22474

一个用于仅解析 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(''))以获得标签之间的提取文本。

组合字符后,我们会遇到一些垃圾字符,例如 '&nbsp;','>' 等。

因此,我们将保留一个噪声表,其中噪声(让我们称之为垃圾字符)将被一个空格替换。完成后,我们将实现我们的目标。

关注点

这篇文章展示了一种使用基于集合的方法解析数据的方法。它还展示了我们如何在单个 Replace 语句中替换数据,而不是多个语句。正如本文所证明的那样,FOR XML PATH 在组合字符方面非常方便。

历史

  • 2010 年 1 月 12 日:初始发布
© . All rights reserved.