使用HtmlAgilityPack选择内部/子元素

时间:2013-02-05 15:48:06

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

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

<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||#text
 audio/mpeg||source

并且nr。儿童的元素是2。

1 个答案:

答案 0 :(得分:1)

第一个问题是您的<source>标记未关闭。 AgilityPack会自动关闭它,第二个<source><embed>标记位于第一个<source>标记内。但是AgilityPack 知道 <embed>是一个自我结束的标签。幸运的是,有一种方法可以说,您希望将标记视为自闭标记:

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