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).

10
demandé sur Devart 2016-08-10 11:44:56

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
7
répondu Devart 2016-08-10 11:28:03

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;
5
répondu LukStorms 2017-04-19 13:33:15

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/

2
répondu cp50 2016-08-10 09:56:48

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...

1
répondu Shnugo 2016-08-12 08:36:38

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
0
répondu Ranjana Ghimire 2016-08-10 08:58:54

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)')
0
répondu StackUser 2016-08-10 09:02:36

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.

0
répondu Zsuzsa 2017-04-13 12:42:39