【问题标题】:Select inner/child Elements with HtmlAgilityPack使用 HtmlAgilityPack 选择内部/子元素
【发布时间】:2023-03-12 12:45:01
【问题描述】:

我想从这个 html-sn-p 中提取两个源属性:

<audio controls>
<source src="horse.mp3" type="audio/mpeg">
<source src="horse.ogg" type="audio/ogg">
<embed height="50" width="100" src="horse.mp3">
</audio>

这是我的工作:

首先,我提取所有音频标签(包括您在上面看到的那个):

var audio_tags = HtmlDoc.DocumentNode.SelectNodes("//" + HTML.TAG_AUDIO); 

之后,我尝试使用这段代码从 HtmlNodeCollection audio_tags 中提取源元素:

foreach (HtmlNode link in audio_tags)
        {
            if (link != null)
            {
                string url;
                string type;
                // select all source tags, see here for an example: http://www.w3schools.com/html/html_sounds.asp
                if(link.HasChildNodes)
                {
                    var children = link.ChildNodes;
                    if (children != null)
                    {
                        foreach (HtmlNode child in children)
                        {
                            Console.WriteLine(children[0].GetAttributeValue("type", "err").ToString() + "||" + children[0].OriginalName);
                            Console.WriteLine(children[1].GetAttributeValue("type", "errrr").ToString() + "||" + children[1].OriginalName);
 ...

写行表明第一个元素不存在,因为打印了“err”。但它应该是第一个源元素。我会很高兴有一些提示。

编辑:

这些文字的输出是:

 err||#text
 audio/mpeg||source

还有nr。子元素的数量是 2。

【问题讨论】:

  • 这个“音频控制”元素是什么? XML 中的元素不能有空格。如果“controls”是一个属性,它必须有一个值。
  • 你对!音频是一个新的 html5 元素。并且here 进行了解释。总结一下:在XHTML中,属性最小化是被禁止的,controls属性必须定义为

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


【解决方案1】:

第一个问题是您的&lt;source&gt; 标签未关闭。 AgilityPack 以这样的方式自动关闭它,第二个 &lt;source&gt; 和 &lt;embed&gt; 标签位于第一个 &lt;source&gt; 标签内。但是 AgilityPack 知道 &lt;embed&gt; 是一个自闭合标签。幸运的是,有一种方法可以说,您希望将标签视为自闭合标签:

HtmlNode.ElementsFlags.Add("source", HtmlElementFlag.Empty);

第二个问题是文本节点。每个换行符/空格序列都被转换为文本节点。我假设你想摆脱它们,所以这些节点可能会被跳过。

最后一个,您可以通过将 LINQ 或 xpath 与 AgilityPack 结合使用来提高代码的可读性。这是一个例子:

doc.LoadHtml(html);
doc.DocumentNode
    .Descendants("audio")
    .SelectMany(a =>
        a.ChildNodes.Where(n => n.GetType() != typeof(HtmlTextNode))
    ).ToList()
    .ForEach(n => 
        Console.WriteLine("{0}||{1}", n.GetAttributeValue("type", "err"), n.OriginalName)
    );

这会让你得到类似的东西:

audio/mpeg||source 
audio/ogg||source 
err||embed

【讨论】:

  • 谢谢,这对我帮助很大。它现在有效。但我不明白:“每个换行符/空格序列都转换为文本节点。”可以举个例子吗?
  • @user1826831:在您的示例中,&lt;source&gt; 标签由换行符和/或空格符号分隔。 AgilityPack 将这些(以及其他)文本块转换为HtmlTextNode。所以在你的&lt;source&gt; 和&lt;embed&gt; 标签之间有HtmlTextNodes。这就是您在输出中得到 #text 值的原因(#text 是文本节点的标志)。
  • 非常感谢。现在我明白了。应该阅读文档;) 是否有任何关于 htmlagilitypack-usage 的教程?
  • @user1826831:推荐these系列文章
猜你喜欢
  • 2012-08-17
  • 2011-12-14
  • 2023-04-02
  • 1970-01-01
  • 2011-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多