web-dev-qa-db-fra.com

Pack d'agilité HTML - supprimer les balises indésirables sans supprimer le contenu?

J'ai vu quelques questions connexes ici, mais elles ne parlent pas exactement du même problème auquel je suis confronté.

Je souhaite utiliser HTML Agility Pack pour supprimer les balises indésirables de mon HTML sans perdre le contenu des balises.

Ainsi, par exemple, dans mon scénario, je voudrais conserver les balises "b", "i" et "u".

Et pour une entrée comme:

<p>my paragraph <div>and my <b>div</b></div> are <i>italic</i> and <b>bold</b></p>

Le code HTML résultant doit être:

my paragraph and my <b>div</b> are <i>italic</i> and <b>bold</b>

J'ai essayé d'utiliser la méthode HtmlNode de Remove, mais elle supprime également mon contenu. Aucune suggestion?

J'ai écrit un algorithme basé sur les suggestions d'Oded. C'est ici. Fonctionne comme un charme.

Il supprime toutes les balises sauf strong, em, u et les nœuds de texte brut.

internal static string RemoveUnwantedTags(string data)
{
    if(string.IsNullOrEmpty(data)) return string.Empty;

    var document = new HtmlDocument();
    document.LoadHtml(data);

    var acceptableTags = new String[] { "strong", "em", "u"};

    var nodes = new Queue<HtmlNode>(document.DocumentNode.SelectNodes("./*|./text()"));
    while(nodes.Count > 0)
    {
        var node = nodes.Dequeue();
        var parentNode = node.ParentNode;

        if(!acceptableTags.Contains(node.Name) && node.Name != "#text")
        {
            var childNodes = node.SelectNodes("./*|./text()");

            if (childNodes != null)
            {
                foreach (var child in childNodes)
                {
                    nodes.Enqueue(child);
                    parentNode.InsertBefore(child, node);
                }
            }

            parentNode.RemoveChild(node);

        }
    }

    return document.DocumentNode.InnerHtml;
}

Comment supprimer récursivement une liste donnée de balises html indésirables d'une chaîne html

J'ai pris la réponse @mathias et amélioré sa méthode d'extension afin que vous puissiez fournir une liste de balises à exclure en tant que List<string> (par exemple. {"a","p","hr"}). J'ai également corrigé la logique pour qu'elle fonctionne récursivement correctement:

public static string RemoveUnwantedHtmlTags(this string html, List<string> unwantedTags)
    {
        if (String.IsNullOrEmpty(html))
        {
            return html;
        }

        var document = new HtmlDocument();
        document.LoadHtml(html);

        HtmlNodeCollection tryGetNodes = document.DocumentNode.SelectNodes("./*|./text()");

        if (tryGetNodes == null || !tryGetNodes.Any())
        {
            return html;
        }

        var nodes = new Queue<HtmlNode>(tryGetNodes);

        while (nodes.Count > 0)
        {
            var node = nodes.Dequeue();
            var parentNode = node.ParentNode;

            var childNodes = node.SelectNodes("./*|./text()");

            if (childNodes != null)
            {
                foreach (var child in childNodes)
                {
                    nodes.Enqueue(child);                       
                }
            }

            if (unwantedTags.Any(tag => tag == node.Name))
            {               
                if (childNodes != null)
                {
                    foreach (var child in childNodes)
                    {
                        parentNode.InsertBefore(child, node);
                    }
                }

                parentNode.RemoveChild(node);

            }
        }

        return document.DocumentNode.InnerHtml;
    }
13
theyetiman

Essayez ce qui suit, vous pourriez le trouver un peu plus net que les autres solutions proposées:

public static int RemoveNodesButKeepChildren(this HtmlNode rootNode, string xPath)
{
    HtmlNodeCollection nodes = rootNode.SelectNodes(xPath);
    if (nodes == null)
        return 0;
    foreach (HtmlNode node in nodes)
        node.RemoveButKeepChildren();
    return nodes.Count;
}

public static void RemoveButKeepChildren(this HtmlNode node)
{
    foreach (HtmlNode child in node.ChildNodes)
        node.ParentNode.InsertBefore(child, node);
    node.Remove();
}

public static bool TestYourSpecificExample()
{
    string html = "<p>my paragraph <div>and my <b>div</b></div> are <i>italic</i> and <b>bold</b></p>";
    HtmlDocument document = new HtmlDocument();
    document.LoadHtml(html);
    document.DocumentNode.RemoveNodesButKeepChildren("//div");
    document.DocumentNode.RemoveNodesButKeepChildren("//p");
    return document.DocumentNode.InnerHtml == "my paragraph and my <b>div</b> are <i>italic</i> and <b>bold</b>";
}
8
Nathan Phillips

Avant de supprimer un nœud, récupérez son parent et son InnerText, puis supprimez le nœud et réaffectez le InnerText au parent.

var parent = node.ParentNode;
var innerText = parent.InnerText;
node.Remove();
parent.AppendChild(doc.CreateTextNode(innerText));
4
Oded

Si vous ne souhaitez pas utiliser le pack d'agilité Html et que vous souhaitez toujours supprimer la balise Html indésirable, vous pouvez le faire comme indiqué ci-dessous.

public static string RemoveHtmlTags(string strHtml)
    {
        string strText = Regex.Replace(strHtml, "<(.|\n)*?>", String.Empty);
        strText = HttpUtility.HtmlDecode(strText);
        strText = Regex.Replace(strText, @"\s+", " ");
        return strText;
    }
3
Dilip0165