Вопрос по webforms, asp.net, csquery, xml-parsing, html-parsing – ASP.NET - анализировать / запрашивать HTML перед передачей и вставлять ссылки на классы CSS

0

Как веб-разработчик, я чувствую, что слишком много времени тратится на 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 child ul 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

@ ChrisCannon - да, он основан на разметке. Расширение разметки ASP.NET часто основано на некоторой начальной разметке. (ps: когда вы комментируете кого-то, кто находится здесь на SO, добавьте префикс @nickname к вашему комментарию, или получатель не знает, что вы сделали комментарий) Simon Mourier
Device Filtering выглядит интересно, но разве это не требует изменения моей разметки на страницах ASPX? Я пытаюсь понять, как я могу сделать это отдельно от моих ASPX-страниц и кода в «глобально» определенном файле. Chris Cannon
ИМХО, такой подход может привести к серьезным проблемам с производительностью (реализация окончательного HTML-кода вместо потоковой передачи его в стандартный поток вывода ответа, его повторная обработка, изменение и т. Д.). В любом случае, вы знакомы с технологией фильтрации устройств ASP.NET Msdn.microsoft.com / EN-US / библиотека / ms178620.aspx)? Это может помочь тому, чего вы пытаетесь достичь. Simon Mourier
У меня нет ответа на этот конкретный метод, но если вы хотите написать повторно используемый CSS, я бы предложил изучить язык, генерирующий CSS, такой как SASS илиМеньш. avesse

Ваш Ответ

2   ответа
2

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>

Ваш общий код обработчика может искать такой элемент, а затем использовать отражение, чтобы найти правильный именованный класс и метод для вызова. Это довольно сложно, и выходит за рамки этого ответа; но если вы хотите построить совершенно новый фреймворк или что-то в этом роде, то вот как вы это сделаете.

Спасибо за ваш ответ, но я должен сказать, что замена движка WebForms кажется сумасшедшей! Но тогда между помешанными и подлинными людьми есть тонкая грань! В какой-то момент я перейду в MVC, но моя главная цель - сократить время, затрачиваемое на добавление классов CSS на многочисленные страницы ASPX и т. Д. Именно здесь CSQuery вступит в игру, и я планирую переопределить метод Render, как описано выше, но затем вызову моя собственная функция, где весь анализ выполняется так эффективно, что метод Render для каждой страницы будет просто оберткой для моей функции AddCssClasses в моем классе CssHelper. Chris Cannon
У меня есть пара вопросов относительно вашего поста: (а) Вы упоминаете, что не все DOM доступны? Просто любопытно! (б) Вы упоминаете, что CsQuery быстрее, чем HAP + Fizzler, но определенно быстрее, чем один HAP? (c) Пожалуйста, уточните «и он имеет обширную поддержку динамических и анонимных типов, чтобы сделать передачу данных (например, набор классов CSS) максимально простой», поскольку я не уверен, каким образом набор классов CSS может быть тип данных? Я думаю, я знаю, что вы имеете в виду, я просто не на 100% Chris Cannon
a) не все свойства элемента DOM были реализованы, во многих случаях, потому что это не имеет смысла в клиентской модели (например, события), в некоторых случаях, потому что свойство в сущности совпадает с атрибутом в этом контексте (например, "HREF") так что это не так важно. б) HAP один действительно очень медленно. Первоначально я провел сложный тест селектора потомков на моем 6-мегабайтном документе с селекторами XML; это заняло минуты. HAP один не индексируется никоим образом. c) Смотрите документацию jquery для "css (map)": Api.jquery.com / CSS и обратитесь к файлу readme на странице Github CsQuery для передачи CSS-реквизитов в качестве объекта anon. Jamie Treworgy
Ой ... "замена движка WebForms кажется чокнутой!" да, я застрял с WebForms в этом старом старом проекте и уже настроил маршрутизацию, чтобы я мог использовать REST-пути, так что это было не так уж и тяжело :), что я могу сказать, что я хакер , То, как вы планируете это делать, безусловно, наиболее разумно для ваших целей, я просто не хотел ничего оставлять на столе! Jamie Treworgy
Еще один комментарий: json против CSS - CsQuery фактически позволит вам напрямую перейти в JSON, например,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 для подробностей. Jamie Treworgy
1

это некоторое время назад в проекте, который сжимал контент на лету: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 и изменить его оттуда.

Мне кажется, это самый простой подход.

Я больше склоняюсь к переопределению метода рендеринга страницы, а затем передаю параметры метода рендеринга моей собственной функции, которая находится в моем собственном классе - где-то еще, где выполняется обработка через анализатор HTML (пока не принято решение). Я немного против реализации своего собственного потокового класса из-за всех методов, которые мне нужно реализовать, и это кажется более сложным. Chris Cannon
На самом деле единственные методы, которые вам действительно нужно реализовать, - это запись и очистка. Все остальное можно игнорировать по большей части, потому что вы не читаете из потока и не ищете (хорошо, что нужно реализовать 3 свойства [CanSeek, CanRead, CanWrite], что занимает около 20 секунд). JaCraig
Ладно, спасибо за советы, но я думаю, что реализация собственного потокового класса излишня для того, что я пытаюсь сделать! Chris Cannon

Похожие вопросы