【问题标题】:get all nodes and its content using htmldocument/HtmlAgilityPack使用 htmldocument/HtmlAgilityPack 获取所有节点及其内容
【发布时间】:2017-01-16 15:52:57
【问题描述】:

我需要从 html 中获取所有节点,然后从该节点中获取文本和子节点,以及相同的内容,但从该子子节点获取。 例如,我有这个 HTML:

<p>This <b>is a <a href="">Link</a></b> with <b>bold</b></p>

所以我需要一种方法来获取 p 节点,然后是非格式化文本(this)、唯一粗体文本(is a)、粗体链接 (Link) 以及其他格式化和非格式化文本。

我知道使用 htmldocument 我可以选择所有节点和子节点,但是,如何获取子节点之前的文本,然后是子节点及其文本/子节点,以便我可以制作html 的渲染版本(“This is a Link with bold”)?

请注意,上面的例子是一个简单的例子。 HTML 将包含更复杂的内容,例如列表、框架、编号列表、三重格式文本等。还要注意,渲染的内容不是问题。我已经这样做了,但以另一种方式。我需要的是仅获取节点及其内容的部分。 另外,我不能忽略任何节点,所以我不能一无所有。并且主节点可以以p、div、frame、ul等开头。

【问题讨论】:

  • 你看到这个question了吗?
  • 如果您谈论 Hasan 的评论,是的,我尝试了一个将 HTML 转换为 XAML 的存储库,但遗憾的是我的应用程序不是那么基本。例如,如果有一个带有X类的div,我需要显示一个图像,或者如果在href中有一个具有特定域的,我需要在点击时调用一些函数。
  • 如评论中所述,没有开箱即用的解决方案。您需要构建自己的解析器,它会根据 HTML 标记手动完成所有工作。接近您要求的另一件事是ScrollableHTMLView
  • 我知道没有像“htmldoc.toxaml();”这样的简单方法,但我要求的是节点列表,但包括未格式化的部分。我的意思是:您可以获取主/根节点及其子节点,然后从该子节点中获取其子节点并继续。但是,如果我是正确的,那孩子只是格式化的节点(粗体、a、ul 等)。同样,我不是要求 2 行解决方案,而是要求使用 htmldocument/htmlagilitypack 改进我的实际(2300 行但有很多解释错误)代码的最佳方法
  • 您可以通过查找“#text”节点来获取任何节点之前的文本。在您的示例中,它将是 &lt;p&gt;&lt;#text&gt;&lt;b&gt;&lt;#text&gt;&lt;a&gt;&lt;#text&gt; 类似的东西。如果您仍然无法弄清楚,请告诉我

标签: c# html uwp html-agility-pack


【解决方案1】:

查看 htmldoc 及其属性后,感谢 @HungCao 的观察,我得到了一种解释 HTML 代码的简单方法。

我的代码作为示例添加它有点复杂,所以我将发布它的精简版。

首先,必须加载 htmlDoc。它可以在任何功能上:

HtmlDocument htmlDoc = new HtmlDocument();
string html = @"<p>This <b>is a <a href="""">Link</a></b> with <b>bold</b></p>";
htmlDoc.LoadHtml(html);

然后我们需要解释每个“主”节点(在本例中为 p),并且根据其类型,我们需要加载 LoopF​​unction(InterNode)

HtmlNodeCollection nodes = htmlDoc.DocumentNode.ChildNodes;

foreach (HtmlNode node in nodes)
{
    if(node.Name.ToLower() == "p") //Low the typeName just in case
    {
        Paragraph newPPara = new Paragraph();
        foreach(HtmlNode childNode in node.ChildNodes)
        {
            InterNode(childNode, ref newPPara);
        }
        richTextBlock.Blocks.Add(newPPara);
    }
}

请注意,有一个名为“NodeType”的属性,但它不会返回正确的类型。因此,改为使用“Name”属性(另请注意,htmlNode 中的 Name 属性与 HTML 中的 Name 属性不同)。

最后,我们有 InterNode 函数,它将内联添加到引用的(参考)段落

public bool InterNode(HtmlNode htmlNode, ref Paragraph originalPar)
{
    string htmlNodeName = htmlNode.Name.ToLower();

    List<string> nodeAttList = new List<string>();
    HtmlNode parentNode = htmlNode.ParentNode;
    while (parentNode != null) {
        nodeAttList.Add(parentNode.Name);
        parentNode = parentNode.ParentNode;
    } //we need to get it multiple types, because it could be b(old) and i(talic) at the same time.

    Inline newRun = new Run();
    foreach (string noteAttStr in nodeAttList) //with this we can set all the attributes to the inline
    {
        switch (noteAttStr)
        {
            case ("b"):
            case ("strong"):
                {
                    newRun.FontWeight = FontWeights.Bold;
                    break;
                }
            case ("i"):
            case ("em"):
                {
                    newRun.FontStyle = FontStyle.Italic;
                    break;
                }
        }
    }

    if(htmlNodeName == "#text") //the #text means that its a text node. Like <i><#text/></i>. Thanks @HungCao
    {
        ((Run)newRun).Text = htmlNode.InnerText;
    } else //if it is not a #text, don't load its innertext, as it's another node and it will always have a #text node as a child (if it has any text)
    {
        foreach (HtmlNode childNode in htmlNode.ChildNodes)
        {
            InterNode(childNode, ref originalPar);
        }
    }

    return true;
}

注意:我知道我说过我的应用程序需要以 webview 的另一种方式呈现 HTML,并且我知道此示例代码生成与 Webview 相同的内容,但是,正如我之前所说,这是只是我最终代码的精简版。事实上,我的原始/完整代码正在按我的需要工作,这只是基础。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多