SQL-supprimer toutes les balises HTML dans une chaîne de caractères
dans mon ensemble de données, j'ai un champ qui stocke du texte marqué avec HTML. Le format général est le suivant:
<html><head></head><body><p>My text.</p></body></html>
je pourrais tenter de résoudre le problème en procédant comme suit:
REPLACE(REPLACE(Table.HtmlData, '<html><head></head><body><p>', ''), '</p></body></html>')
Toutefois, ce n'est pas une règle stricte que certaines entrées ne respectent pas les normes du W3C et ne comprennent pas <head>
tags par exemple. Pire encore, il pourrait y avoir manque de fermeture de balises. Donc j'aurais besoin d'inclure l' REPLACE
fonction pour chaque étiquette d'ouverture et de fermeture qui pourrait exister.
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
Table.HtmlData,
'<html>', ''),
'</html>', ''),
'<head>', ''),
'</head>', ''),
'<body>', ''),
'</body>', ''),
'<p>', ''),
'</p>', '')
je me demandais s'il n'y avait pas une meilleure façon d'accomplir ceci que d'utiliser plusieurs imbriqués REPLACE
fonctions. Malheureusement, les seules langues disponibles dans cet environnement sont SQL et Visual Basic (pas .NET).
7 réponses
DECLARE @x XML = '<html><head></head><body><p>My text.</p></body></html>'
SELECT t.c.value('.', 'NVARCHAR(MAX)')
FROM @x.nodes('*') t(c)
mise à jour-pour les chaînes avec des tags non clos:
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
si le HTML est bien formé, il n'est pas nécessaire d'utiliser replace pour analyser XML.
Il suffit de le lancer ou de le convertir en un type XML et d'obtenir la(Les) valeur (s).
voici un exemple pour afficher le texte de toutes les balises:
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)');
notez qu'il y a une différence dans la sortie des espaces blancs entre cast et convert.
pour obtenir seulement le contenu d'un noeud spécifique, le XQuery la syntaxe est utilisée. (XQuery est basé sur le XPath syntaxe)
Par exemple:
select cast(@htmlData as XML).value('(//body/p/node())[1]', 'nvarchar(max)');
select convert(XML,@htmlData,1).value('(//body/p/node())[1]', 'nvarchar(max)');
Résultat : My text.
bien sûr, cela suppose toujours un XML valide.
Si par exemple, une balise de fermeture est manquant, alors cela poserait un XML parsing
erreur.
si le HTML n'est pas bien formé comme un XML, alors on pourrait utiliser PATINDEX & SUBSTRING pour obtenir la première balise p. Et ensuite le lancer dans un type XML pour obtenir la valeur.
select cast(SUBSTRING(@htmlData,patindex('%<p>%',@htmlData),patindex('%</p>%',@htmlData) - patindex('%<p>%',@htmlData)+4) as xml).value('.','nvarchar(max)');
ou via un funky récursive façon:
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;
tout D'abord créer une fonction définie par l'utilisateur qui supprime le HTML comme suit:
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
Lorsque vous essayez de sélectionner:
SELECT dbo.udf_StripHTML([column]) FROM SOMETABLE
ceci devrait vous conduire à éviter d'avoir à utiliser plusieurs instructions de remplacement imbriquées.
crédit et plus d'informations: http://blog.sqlauthority.com/2007/06/16/sql-server-udf-user-defined-function-to-strip-html-parse-html-no-regular-expression/
une solution de plus, juste pour montrer un truc pour remplacer de nombreuses valeurs d'une table (facile à entretenir!!!) en une seule instruction:
--ajouter tout remplacent les modèles ici:
CREATE TABLE ReplaceTags (HTML VARCHAR(100));
INSERT INTO ReplaceTags VALUES
('<html>'),('<head>'),('<body>'),('<p>'),('<br>')
,('</html>'),('</head>'),('</body>'),('</p>'),('</br>');
GO
--Cette fonction sera d'effectuer le "truc"
CREATE FUNCTION dbo.DoReplace(@Content VARCHAR(MAX))
RETURNS VARCHAR(MAX)
AS
BEGIN
SELECT @Content=REPLACE(@Content,HTML,'')
FROM ReplaceTags;
RETURN @Content;
END
GO
--Tous les exemples que j'ai trouvé dans votre question et dans les commentaires
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>');
-- c'est le réel requête
SELECT dbo.DoReplace(Content) FROM @content;
GO
-- Nettoyage
DROP FUNCTION dbo.DoReplace;
DROP TABLE ReplaceTags;
UPDATE
si vous ajoutez une valeur de remplacement à la table template, vous pourriez même utiliser des valeurs différentes comme remplacer un <br>
avec un saut de ligne...
ce n'est qu'un exemple. Vous pouvez l'utiliser dans script pour remplacer n'importe quelle balise 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
C'est la façon la plus simple.
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)')
vous mentionnez que le XML n'est pas toujours valide, mais contient-il toujours les balises
et
?Dans ce cas, la suivante devrait fonctionner:
SUBSTRING(Table.HtmlData,
CHARINDEX('<p>', Table.HtmlData) + 1,
CHARINDEX('</p>', Table.HtmlData) - CHARINDEX('<p>', Table.HtmlData) + 1)
pour trouver toutes les positions d'un
dans un HTML, il y a déjà un bon post ici: https://dba.stackexchange.com/questions/41961/how-to-find-all-positions-of-a-string-within-another-string
alternativement je suggère D'utiliser Visual Basic, comme vous l'avez mentionné qui est aussi un option.