私のデータセットには、HTMLでマークアップされたテキストを格納するフィールドがあります。一般的な形式は次のとおりです。
<html><head></head><body><p>My text.</p></body></html>
次のことを行うことで問題の解決を試みることができます。
REPLACE(REPLACE(Table.HtmlData, '<html><head></head><body><p>', ''), '</p></body></html>')
ただし、これはエントリの一部がW3C標準を破るであり、たとえば<head>
タグを含まないため、厳密な規則ではありません。さらに悪いことに、終了タグが欠落している可能性があります。そのため、存在する可能性のある開始タグと終了タグごとにREPLACE
関数を含める必要があります。
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
Table.HtmlData,
'<html>', ''),
'</html>', ''),
'<head>', ''),
'</head>', ''),
'<body>', ''),
'</body>', ''),
'<p>', ''),
'</p>', '')
複数のネストされたREPLACE
関数を使用するよりも、これを達成するためのより良い方法があるかどうか疑問に思っていました。残念ながら、この環境で使用できる言語はSQLとVisual Basic(.NETではありません)のみです。
DECLARE @x XML = '<html><head></head><body><p>My text.</p></body></html>'
SELECT t.c.value('.', 'NVARCHAR(MAX)')
FROM @x.nodes('*') t(c)
更新-タグが閉じられていない文字列の場合:
DECLARE @x NVARCHAR(MAX) = '<html><head></head><body><p>My text.<br>More text.</p></body></html>'
SELECT x.value('.', 'NVARCHAR(MAX)')
FROM (
SELECT x = CAST(REPLACE(REPLACE(@x, '>', '/>'), '</', '<') AS XML)
) r
HTMLが整形式であれば、XMLを解析するために置換を使用する必要はありません。
それをXML型にキャストまたは変換し、値を取得するだけです。
すべてのタグからテキストを出力する例を次に示します。
declare @htmlData nvarchar(100) = '<html>
<head>
</head>
<body>
<p>My text.</p>
<p>My other text.</p>
</body>
</html>';
select convert(XML,@htmlData,1).value('.', 'nvarchar(max)');
select cast(@htmlData as XML).value('.', 'nvarchar(max)');
キャストと変換では、空白の出力に違いがあることに注意してください。
特定のノードからのみコンテンツを取得するには、 XQuery 構文が使用されます。 (XQueryはXPath構文に基づいています)
例えば:
select cast(@htmlData as XML).value('(//body/p/node())[1]', 'nvarchar(max)');
select convert(XML,@htmlData,1).value('(//body/p/node())[1]', 'nvarchar(max)');
結果:My text.
もちろん、これはまだ有効なXMLを前提としています。
たとえば、終了タグがない場合、XML parsing
エラー。
HTMLの形式がXMLとして適切でない場合、PATINDEXとSUBSTRINGを使用して最初のpタグを取得できます。そして、それをXML型にキャストして値を取得します。
select cast(SUBSTRING(@htmlData,patindex('%<p>%',@htmlData),patindex('%</p>%',@htmlData) - patindex('%<p>%',@htmlData)+4) as xml).value('.','nvarchar(max)');
またはファンキーな再帰的な方法で:
declare @xmlData nvarchar(100);
WITH Lines(n, x, y) AS (
SELECT 1, 1, CHARINDEX(char(13), @htmlData)
UNION ALL
SELECT n+1, y+1, CHARINDEX(char(13), @htmlData, y+1) FROM Lines
WHERE y > 0
)
SELECT @xmlData = concat(@xmlData,SUBSTRING(@htmlData,x,IIF(y>0,y-x,8)))
FROM Lines
where PATINDEX('%<p>%</p>%', SUBSTRING(@htmlData,x,IIF(y>0,y-x,10))) > 0
order by n;
select
@xmlData as xmlData,
convert(XML,@xmlData,1).value('(/p/node())[1]', 'nvarchar(max)') as FirstP;
まず、次のようにHTMLを削除するユーザー定義関数を作成します。
CREATE FUNCTION [dbo].[udf_StripHTML] (@HTMLText VARCHAR(MAX))
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE @Start INT;
DECLARE @End INT;
DECLARE @Length INT;
SET @Start = CHARINDEX('<', @HTMLText);
SET @End = CHARINDEX('>', @HTMLText, CHARINDEX('<', @HTMLText));
SET @Length = (@End - @Start) + 1;
WHILE @Start > 0
AND @End > 0
AND @Length > 0
BEGIN
SET @HTMLText = STUFF(@HTMLText, @Start, @Length, '');
SET @Start = CHARINDEX('<', @HTMLText);
SET @End = CHARINDEX('>', @HTMLText, CHARINDEX('<', @HTMLText));
SET @Length = (@End - @Start) + 1;
END;
RETURN LTRIM(RTRIM(@HTMLText));
END;
GO
選択しようとしているとき:
SELECT dbo.udf_StripHTML([column]) FROM SOMETABLE
これにより、ネストされた複数の置換ステートメントを使用する必要がなくなります。
1つのステートメントでテーブルの多くの値(保守しやすい!!!)を置き換えるトリックを示すためのもう1つのソリューション:
-置換テンプレートをここに追加:
CREATE TABLE ReplaceTags (HTML VARCHAR(100));
INSERT INTO ReplaceTags VALUES
('<html>'),('<head>'),('<body>'),('<p>'),('<br>')
,('</html>'),('</head>'),('</body>'),('</p>'),('</br>');
GO
-この関数は「トリック」を実行します
CREATE FUNCTION dbo.DoReplace(@Content VARCHAR(MAX))
RETURNS VARCHAR(MAX)
AS
BEGIN
SELECT @Content=REPLACE(@Content,HTML,'')
FROM ReplaceTags;
RETURN @Content;
END
GO
-質問とコメントで見つかったすべての例
DECLARE @content TABLE(Content VARCHAR(MAX));
INSERT INTO @content VALUES
('<html><head></head><body><p>My text.</p></body></html>')
,('<html><head></head><body><p>My text.<br>More text.</p></body></html>')
,('<html><head></head><body><p>My text.<br>More text.</p></body></html>')
,('<html><head></head><body><p>My text.</p></html>');
-これは実際のクエリです
SELECT dbo.DoReplace(Content) FROM @content;
GO
- 掃除
DROP FUNCTION dbo.DoReplace;
DROP TABLE ReplaceTags;
テンプレートテーブルにreplace-valueを追加すると、replace a <br>
実際の改行あり...
XMLは常に有効であるとは言えませんが、常に<p>および</ p>タグが含まれていますか?
その場合、次のように機能します。
SUBSTRING(Table.HtmlData,
CHARINDEX('<p>', Table.HtmlData) + 1,
CHARINDEX('</p>', Table.HtmlData) - CHARINDEX('<p>', Table.HtmlData) + 1)
HTML内の<p>のすべての位置を見つけるために、ここにすでに良い投稿があります: https://dba.stackexchange.com/questions/41961/how-to-find-all-positions-of- a-string-within-another-string
別の方法として、Visual Basicを使用することをお勧めします。これはオプションでもあります。
SSMS 2017には、正規表現を検索して置換する組み込み機能がありますが、クエリを使用してそれを行う方法がわかりません。
ここでの回答のいくつかは_XML parsing
_を使用しますが、このメソッドは単純なhtml文字列に対してのみ機能し、エラーを返します:_XML parsing: line 5, character 6, end tag does not match start tag
_は複雑なhtml文字列で、ヘルプデスクシステムから取得するこのようなものです。
_'<!--html--><div>
<div>A sentence.</div>
<br>
<div>Thank you!</div>
</div>'
_
結局、再帰CTEを使用して仕事を終わらせました。これが私の機能です。
_ALTER FUNCTION [dbo].[udf_removeHtmlTags]
(
@html NVARCHAR(MAX)
)
RETURNS NVARCHAR(MAX)
AS
BEGIN
DECLARE @returnHtml NVARCHAR(MAX)
;with cte(id, html) as (
select 1, STUFF(@html, CHARINDEX('<', @html), CHARINDEX('>', @html)-CHARINDEX('<', @html)+1, '')
union all
select id + 1, STUFF(html, CHARINDEX('<', html), CHARINDEX('>', html)-CHARINDEX('<', html)+1, '')
from cte
where html like '%<%>%'
)
select top 1 @returnHtml = html
from cte
order by id desc
RETURN @returnHtml
END
_
これは単なる例です。スクリプトでこれを使用して、htmlタグを削除できます。
DECLARE @VALUE VARCHAR(MAX),@start INT,@end int,@remove varchar(max)
SET @VALUE='<html itemscope itemtype="http://schema.org/QAPage">
<head>
<title>sql - Converting INT to DATE then using GETDATE on conversion? - Stack Overflow</title>
<html>
</html>
'
set @start=charindex('<',@value)
while @start>0
begin
set @end=charindex('>',@VALUE)
set @remove=substring(@VALUE,@start,@end)
set @value=replace(@value,@remove,'')
set @start=charindex('<',@value)
end
print @value
これが最も簡単な方法です。
DECLARE @str VARCHAR(299)
SELECT @str = '<html><head></head><body><p>My text.</p></body></html>'
SELECT cast(@str AS XML).query('.').value('.', 'varchar(200)')