可以获得HtmlNode的位置&原始输入内的长度?

时间:2012-10-12 15:08:10

标签: c# .net html-agility-pack

考虑以下HTML片段(_用于空格):

<head>
    ...
    <link ... ___/>
    <!-- ... -->
    ...
</head>

我正在使用Html Agility Pack(HAP)来读取HTML文件/片段并删除链接。我想要做的是找到LINK(以及其他一些)元素,然后用空格替换它们,如下所示:

<head>
    ...
    ____________
    <!-- ... -->
    ...
</head>

到目前为止,解析部分似乎正在工作,我得到了我正在寻找的节点。但是,HAP尝试修复HTML内容,而我需要的所有内容完全相同,除了我正在尝试进行的更改。另外,HAP在回写之前读过的内容时似乎有很多错误,所以我想采取的方法是让HAP解析输入,然后我回到原始输入并替换我的内容不想要。

问题是,HtmlNode似乎没有输入长度属性。它有StreamPosition,它似乎表明在输入中读取节点内容的位置,但我找不到一个长度属性,它告诉我构建节点消耗了多少字符。

我尝试使用OuterHtml广告,但不幸的是,HAP尝试通过删除LINK部分来修复___/LINK元素不应该被关闭)。因此,OuterHtml.Length返回错误的长度。

HAP中是否有办法获取此信息?

3 个答案:

答案 0 :(得分:3)

我最终修改了HtmlAgilityPack的代码,以公开一个返回_outerlength的私有HtmlNode字段的新属性。

public virtual int OuterLength
{
    get
    {
        return ( _outerlength );
    }
}

到目前为止,这似乎工作正常。

答案 1 :(得分:2)

如果要在不重新编译HAP的情况下获得相同的结果,请使用反射来访问私有变量。

我通常不建议使用反射来访问私有变量,但我最近遇到了与此完全相同的情况并使用了反射,因为我无法使用重新编译的程序集版本。为此,请创建一个包含字段信息对象的静态变量(以避免在每次使用时重新创建它):

private static readonly FieldInfo HtmlNodeOuterLengthFieldInfo = typeof(HtmlNode).GetField("_outerlength", BindingFlags.NonPublic | BindingFlags.Instance);

然后,只要您想访问原始外部HTML的真实长度:

var match = htmlDocument.DocumentNode.SelectSingleNode("xpath");
var htmlLength = (int)HtmlNodeOuterLengthFieldInfo.GetValue(match);

答案 2 :(得分:1)

将@Xcalibur的答案转换为扩展方法。

请注意,HtmlNode具有属性OuterLength,但它与私有字段_outerlength不同,这正是我们所需要的。 (在这里阅读其他答案,我首先想到,自2013年以来,HtmlAgilityPack已将OuterLength作为公共属性添加,他们这样做了,但是经过一些测试,我注意到它只是返回了OuterHtml的长度)。因此,我们可以从源头重建程序包以将字段公开为公共属性,也可以使用带有Reflection的扩展方法(速度很慢)。

扩展方法

namespace HtmlAgilityPack
{
    public static class HtmlDocumentExtensions
    {
        private static readonly System.Reflection.FieldInfo HtmlNodeOuterLengthFieldInfo = 
          typeof(HtmlNode).GetField("_outerlength", System.Reflection.BindingFlags.NonPublic 
          | System.Reflection.BindingFlags.Instance);

        public static int GetOuterLengthInStream(this HtmlNode node) => 
          (int)HtmlNodeOuterLengthFieldInfo.GetValue(node ?? 
          throw new System.ArgumentNullException(nameof(node)));
    }
}

由于HtmlNode已经具有属性OuterLength,为避免歧义,我将方法称为GetOuterLengthInStream()

用法

node.GetOuterLengthInStream()