0

作为一名 Web 开发人员,我觉得我的太多时间都花在了 CSS 上。我正在尝试提出一个解决方案,我可以编写可重用的 CSS即类并在 HTML 中引用这些类,而无需在 ASPX 或 ASCX 文件等或代码隐藏文件中添加额外代码。我想要一个将 HTML 元素与 CSS 类链接起来的中介。

我想要达到的目标:

  • 在传输前立即修改 HTML
  • 选择 HTML 中的元素
  • 基于其他地方定义的规则(例如在与当前正在处理的页面相关的文本文件中):
  • 向多个 HTML 元素添加 CSS 类引用
  • 多个 CSS 类引用添加到单个 HTML 元素

我如何设想这个工作:

  1. 扩展生成最终 HTML 的 ASP.NET 函数
  2. 将所有 HTML 作为字符串抓取
  3. 将字符串传递给具有查询(例如 XPATH)方法的对象的构造函数
  4. 浏览全局规则列表,例如ul先的孩子,div然后class = "navigation"
  5. 浏览页面特定规则的列表,例如对于ul第一个div然后的孩子class &= " home"
  6. 从对象获取已处理的 HTML,例如 obj.ToString
  7. ASP.NET 使用已处理的 HTML 恢复页面生成

所以我需要知道的是:

  1. 在哪里/如何扩展 ASP.NET 页面生成功能(获取页面的所有 HTML)
  2. 哪些类有元素/节点查询方法和属性访问

提前感谢您的帮助。

PS 我正在开发 ASP.NET Web 表单网站,其中包含在 ISS 7 上运行的 VB.net 代码隐藏

4

2 回答 2

2

查看我的 CsQuery 项目:https ://github.com/jamietre/csquery或在 nuget 上作为“CsQuery”。

这是 jQuery 的 C# (.NET 4) 端口。在基本性能测试(包含在项目测试套件中)中,选择器比 HTML Agility Pack + Fizzler(HAP 的 css 选择器插件)快大约 100 倍;在典型的网站上实时操作输出流非常快。如果你是 amazon.com 什么的,当然是 YMMV。

我开发它的最初目的是从内容管理系统中操作 HTML。启动并运行它后,我发现使用 CSS 选择器和 jQuery API 比使用 Web 控件有趣得多,并开始将其用作服务器渲染页面的主要 HTML 操作工具,并将其构建为涵盖几乎所有的 CSS、jQuery 和浏览器 DOM。从那以后我就再也没有碰过网络控件。

要使用 CsQuery 拦截 Web 表单中的 HTML,您可以在页面代码隐藏中执行以下操作:

using CsQuery;
using CsQuery.Web;

protected override void Render(HtmlTextWriter writer)
{

    var csqContext = WebForms.CreateFromRender(Page, base.Render, writer);

    // CQ object is like a jQuery object. The "Dom" property of the context
    // returned above represents the output of this page.

    CQ doc = csqContext.Dom;

    doc["li > a"].AddClass("foo");

    // write it
    csqContext.Render();
}

要在 ASP.NET MVC 中做同样的事情,请参阅描述该内容的博客文章

GitHub 上有 CsQuery 的基本文档。除了输入和输出 HTML 之外,它的工作方式与 jQuery 非常相似。上面的WebForms对象只是为了帮助您处理与HtmlTextWriter对象和Render方法的交互。通用用法很简单:

var doc = CQ.Create(htmlString);

// or (useful for scraping and testing)
var doc = CQ.CreateFromUrl(url);

// do stuff with doc, a CQ object that acts like a jQuery object

doc["table tr:first"].Append("<td>A new cell</td>");

此外,几乎整个浏览器 DOM 都可以使用您在浏览器中使用的相同方法获得。索引器 [0] 返回选择集中的第一个元素,如 jquery;如果您习惯编写 javascript 来操作 HTML,那么应该非常熟悉。

// "Select" method is the same as the property indexer [] we used above.
// I go back and forth between them to emphasise their interchangeability.

var element = dom.Select("div > input[type=checkbox]:first-child")[0];
a.Checked=true;

当然,在 C# 中,您可以使用大量其他通用工具,例如 LINQ。或者:

var element = dom["div > input[type=checkbox]:first-child"].Single();

a.Checked=true; 

完成对文档的操作后,您可能希望获取 HTML:

string html = doc.Render();

这里的所有都是它的。对象上有大量的方法CQ,涵盖了所有 jQuery DOM 操作技术。还有一些处理 JSON 的实用方法,它对动态和匿名类型有广泛的支持,以使传递数据结构(例如一组 CSS 类)尽可能容易——就像 jQuery 一样。

一些更高级的东西

我不建议这样做,除非您熟悉 asp.net 的 http 工作流程的低级修补。没有什么是可以撤消的,但是如果您从未听说过 HttpHandler,将会有一个学习曲线。

如果您想完全跳过 WebForms 引擎,您可以创建一个IHttpHandler自动解析 HTML 文件的引擎。这肯定会比覆盖在 ASPX 引擎上执行得更好——谁知道呢,甚至可能比使用 Web 控件进行类似数量的服务器端处理还要快。然后,您可以使用 web.config为特定扩展名(如htmhtml)注册您的处理程序。

另一种自动拦截的方法是使用路由。您可以在 webforms 应用程序中毫无问题地使用 MVC 路由库,这里有一个关于如何做到这一点的描述。然后,您可以创建一个匹配您想要的任何模式的路由(同样,也许*.html)并将处理传递给自定义IHttpHandler或类。在这种情况下,您正在做所有事情:您需要查看路径,从文件系统加载文件,使用 CsQuery 解析它,然后流式传输响应。

当然,使用任何一种机制,您都需要一种方法来告诉您的项目为每个页面运行什么代码。也就是说,仅仅因为您已经创建了一个漂亮的 HTML 解析器,那么您如何告诉它为该页面运行正确的“隐藏代码”?

MVC 通过定位一个名称为“PageNameController.cs”的控制器并调用与参数名称匹配的方法来做到这一点。你可以为所欲为;例如,您可以添加一个元素:

<script type="controller" src="MyPageController"></script>

您的通用处理程序代码可以查找这样的元素,然后使用反射来定位要调用的正确命名类和方法。这非常复杂,超出了这个答案的范围;但是,如果您正在寻找构建一个全新的框架或其他东西,这就是您将如何去做的事情。

于 2012-06-14T18:34:48.010 回答
1

在发送页面之前拦截页面内容是相当简单的。不久前,我在一个动态压缩内容的项目上做了这个:http: //optimizerprime.codeplex.com/(它很丑,但它完成了它的工作,你也许可以挽救一些代码)。无论如何,您想要做的是以下内容:

1) 创建一个 Stream 对象,保存页面的内容,直到 Flush 被调用。例如,我在压缩项目中使用了它:http: //optimizerprime.codeplex.com/SourceControl/changeset/view/83171#1795869就像我之前说的,它并不漂亮。但我的观点是,您需要创建自己的 Stream 类来执行您想要的操作(在这种情况下,为您提供页面的字符串输出,解析/修改字符串,然后将其输出给用户)。

2)将页面的过滤器对象分配给它。(Page.Response.Filter) 请注意,您需要尽早执行此操作,以便捕获所有内容。我使用在 PreRequestHandlerExecute 事件上运行的 HTTP 模块来完成此操作。但是如果你做了这样的事情:

    protected override void OnPreInit(EventArgs e)
    {
        this.Response.Filter = new MyStream();
        base.OnPreInit(e);
    }

这也很可能奏效。

3)您应该能够使用Html Agility Pack之类的东西来解析 HTML 并从那里修改它。

对我来说,这似乎是最简单的方法。

于 2012-06-14T19:07:07.860 回答