JQuery HtmlAgilityPack 中的“.closest()”等价物?

JQuery ".closest()" equivalent in HtmlAgilityPack?

我正在使用 HtmlAgilityPack。有没有类似jQueryclosest的功能? (与 CSS 选择器匹配的最近父级)。我尝试了 google 和网站 http://html-agility-pack.net - 两者似乎都没有答案。

我需要同样的东西,但找不到,所以我写了自己的 Closest 函数:

public static HtmlNode Closest(this HtmlNode node, string search)
{
    search = search.ToLower();
    while (node.ParentNode != null)
    {
        if (node.ParentNode.Name.ToLower() == search) return node.ParentNode;
        node = node.ParentNode;
    }
    return null;
} 

这个仅适用于标签名称(正如我所需要的),您可以将其扩展到 类、属性和...

目前没有内置方法,可以自己写一个Extension method来实现

我写了一个简单的扩展方法,可用于查找名称为 tagNameIDclass 的元素。

无论如何,它可以很容易地进一步扩展以匹配其他选择器。

public static class HtmlAgilityPackExtensions
{
    public static HtmlNode Closest(this HtmlNode node, string jQuerySelector)
    {
        if (node == null) return null;
        string tagName = "", id = "";
        var classes = new List<string>();

        if (jQuerySelector.Contains("."))
        {
            var parts = jQuerySelector.Split('.');

            if (!string.IsNullOrWhiteSpace(parts[0]))
            {
                tagName = parts[0];
            }

            for (int i = 1; i < parts.Length; i++)
            {
                classes.Add(parts[i]);
            }
        }

        if (jQuerySelector.Contains("#"))
        {
            var parts = jQuerySelector.Split('#');

            if (!string.IsNullOrWhiteSpace(parts[0]))
            {
                tagName = parts[0];
            }

            id = parts[1];
        }

        if (string.IsNullOrWhiteSpace(tagName) && string.IsNullOrWhiteSpace(id) && classes.Count == 0)
        {
           tagName = jQuerySelector;
        }

        HtmlNode closestParent = null;

        while (node.ParentNode != null && closestParent == null)
        {
            var isClosest = true;
            node = node.ParentNode;

            if (!string.IsNullOrWhiteSpace(tagName))
            {
                isClosest = node.Name == tagName;
            }

            if (isClosest && !string.IsNullOrWhiteSpace(id))
            {
                isClosest = node.Id == id;
            }

            if (isClosest && classes.Count > 0)
            {
                var classNames = node.GetAttributeValue("class", "");
                if (!string.IsNullOrWhiteSpace(classNames))
                {
                    foreach (string c in classes)
                    {
                        isClosest = classNames.Contains(c);
                        if (!isClosest) break;
                    }
                }
            }

            if (isClosest)
            {
                closestParent = node;
            }
        }

        return closestParent;
    }
}

测试代码

       var html = "<div><div id='parent1' class='parent'><span id='parent2' class='parent'><div id='parent3' class='parent'><div id='TestNode' class='child'>Test node</div></div></span></div></div>";
        var htmlDoc = new HtmlDocument();
        htmlDoc.LoadHtml(html);

        var testNode1 = htmlDoc.DocumentNode.SelectSingleNode("//div[@id='TestNode']");
        if (testNode1 != null)
        {
            var parent1 = testNode1.Closest(".parent");
            var parent2 = testNode1.Closest("#parent1");
            var parent3 = testNode1.Closest("span.parent");
            var nonExistingParent = testNode1.Closest("span.parent1");
        }