Вопрос по webforms, asp.net, csquery, xml-parsing, html-parsing – ASP.NET - анализировать / запрашивать HTML перед передачей и вставлять ссылки на классы CSS
Как веб-разработчик, я чувствую, что слишком много времени тратится на CSS. Я пытаюсь найти решение, в котором я могу написатьre-usable CSS то есть классы и ссылки на эти классы в HTML без дополнительного кода в файлах ASPX или ASCX и т. д. или файлов с выделенным кодом. Я хочуintermediary который связывает элементы HTML с классами CSS.
Чего я хочу добиться:
Modify HTML immediately before transmission Select elements in the HTML Based on rules defined elsewhere (e.g. in a text file relating to the page currently being processed): Add a CSS class reference to multiple HTML elements Add multiple CSS class references to a single HTML elementКак я это себе представляю
Extend ASP.NET functions which generate final HTML Grab all the HTML as a string Pass the string into a contructor for an object with querying (e.g. XPATH) methods Go through list of global rules e.g. for childul
of first div
then class = "navigation"
Go through list of page specific rules e.g. for child ul
of first div
then class &= " home"
Get processed HTML from object e.g. obj.ToString
ASP.NET to resume page generation using processed HTML
So what I need to know is:
Where / how can I extend ASP.NET page generation functions (to get all HTML of page) What classes have element / node querying methods and access to attributesЗаранее благодарны за Вашу помощь.
Постскриптум Я занимаюсь разработкой веб-форм ASP.NET с использованием кода VB.net на ISS 7
https: //github.com/jamietre/csquer или на nuget как "CsQuery".
Это порт jQuery на C # (.NET 4). В базовых тестах производительности (включенных в набор тестов проекта) селекторы примерно в 100 раз быстрее, чем HTML Agility Pack + Fizzler (надстройка селектора CSS для HAP); это достаточно быстро для манипулирования потоком вывода в реальном времени на типичном веб-сайте. Если вы amazon.com или что-то, конечно, YMMV.
Моей первоначальной целью при разработке этого было манипулирование HTML из системы управления контентом. После того, как я его запустил, я обнаружил, что использовать селекторы CSS и API jQuery гораздо интереснее, чем веб-элементы управления, и начал использовать его в качестве основного инструмента HTML-манипулирования для страниц, отображаемых на сервере, и создал его для почти все CSS, jQuery и DOM браузера. С тех пор я не касался веб-элемента управления.
Чтобы перехватить HTML в веб-формах с помощью CsQuery, вы делаете это на странице кода:
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.
Некоторые более продвинутые вещи
Я не рекомендую делать это, если вы не знакомы с работой на низком уровне с http-процессом asp.net. Ничто не может быть отменено, но будет кривая обучения, если вы никогда не слышали о HttpHandler.
Если вы хотите вообще пропустить движок WebForms, вы можете создатьIHttpHandler
, который автоматически анализирует HTML-файлы. Это определенно будет работать лучше, чем наложение на движок ASPX - кто знает, может быть, даже быстрее, чем выполнять аналогичную обработку на стороне сервера с веб-элементами управления. Вы можете тогда зарегистрируйте свой обработчик, используя web.config для определенных расширений (например,htm
а такжеhtml
).
Еще один способ автоматического перехвата - это маршрутизация. Вы можете без проблем использовать библиотеку маршрутизации MVC в приложении webforms, вот одно описание того, как это сделать. Затем вы можете создать маршрут, который соответствует любому шаблону, который вы хотите (опять же, возможно,*.html
) и передать обработку пользовательскомуIHttpHandler
или класс. В этом случае вы делаете все: вам нужно посмотреть путь, загрузить файл из файловой системы, проанализировать его с помощью CsQuery и направить ответ.
Используя любой из этих механизмов, вам, конечно, понадобится указать вашему проекту, какой код запускать для каждой страницы. То есть, если вы создали изящный HTML-парсер, как вы тогда скажете ему запустить правильный «код позади» для этой страницы?
MVC делает это, просто находя контроллер с именем «PageNameController.cs» и вызывая метод, который соответствует имени параметра. Вы можете делать все, что хотите; например Вы можете добавить элемент:
<script type="controller" src="MyPageController"></script>
Ваш общий код обработчика может искать такой элемент, а затем использовать отражение, чтобы найти правильный именованный класс и метод для вызова. Это довольно сложно, и выходит за рамки этого ответа; но если вы хотите построить совершенно новый фреймворк или что-то в этом роде, то вот как вы это сделаете.
doc["div > span"].CssSet("{ \"height\": 10, \"width\": 10}");
добавит css стили height & width со значениями 10 на всех дочерних элементах span первого и всех div. Вы также можете использовать объекты, например,doc["div > span"].CssSet(new { height=10, width=10});
делает то же самое с анонимным объектом. Смотрите readme на github для подробностей.
это некоторое время назад в проекте, который сжимал контент на лету:http: //optimizerprime.codeplex.com (Это некрасиво, но это сработало, и вы могли бы спасти часть кода). В любом случае, вы хотите сделать следующее:
1) Создайте объект Stream, который сохраняет содержимое страницы до вызова Flush. Например, я использовал это в своем проекте сжатия:http: //optimizerprime.codeplex.com/SourceControl/changeset/view/83171#179586 Как я уже говорил, это не красиво. Но я хочу сказать, что вам нужно создать собственный класс Stream, который будет делать то, что вы хотите (в этом случае вы получите строковый вывод страницы, проанализируете / измените строку и затем выведете ее для пользователя).
2) Назначьте ему объект фильтра страницы. (Page.Response.Filter) Обратите внимание, что вам нужно сделать это довольно рано, чтобы вы могли поймать весь контент. Я сделал это с модулем HTTP, который работал на событии PreRequestHandlerExecute. Но если вы сделали что-то вроде этого:
protected override void OnPreInit(EventArgs e)
{
this.Response.Filter = new MyStream();
base.OnPreInit(e);
}
Это также, скорее всего, сработает.
3) Вы должны быть в состоянии использовать что-то вродеHtml Agility Pack чтобы разобрать HTML и изменить его оттуда.
Мне кажется, это самый простой подход.