Представьте такую парсилку:
1. Сначала разобрать HTML-документ на линейную последовательность тегов. Линейную, карл. Никаких отношений между тегами. Парсер не знает про то, что теги вложены друг в друга, имеют закрывающих собратьев и другое. Тег - имя + набор атрибутов. Иерархии нет. Закрывающий тег - тупо отдельное имя в той же плоской последовательности. Есть тег «TD», а есть тег «/TD», у них просто вот такие имена и парсеру неважно почему они такие. Какой-нибудь простой текст будет в итоге превращён в объект-тег типа «TEXT» с атрибутом value равный самому тексту, допустим.
2. Рассмотреть всю эту последовательность как строку, где вместо char объект «тег» (с атрибутами).
3. Сделать как-бы regexp-машинку, но не совсем regexp: она оперирует не символами текста (char), а этими самыми объектами-тегами, линейно следующими, как обычный текст.
В таком духе:
// заматчить любую пару тегов <TD> + </TD> с любыми тегами между ними.
// повторю: здесь всем пофиг на имена тегов. Никаких отношений между TD и /TD парсер HTML и данная regexp-машина не знают. Для неё это просто 2 каки-то там тега.
TD, * *, /TD
// то же самое, но только <TD> имеющий атрибут "hello" равный 123
TD hello=="123", * *, /TD
// можно замутить встроенный язык с переменными
// При встрече тега HTML создать i = 0
// Пропустить сколько угодно каких угодно тегов
// заматчить много последовательностей <TD> ... </TD>
// При матчинге очередного TD инкрементнуть переменную
// В итоге мы посчитаем число пар <TD>...</TD> заодно.
HTML $i=0, * *, (TD $i++, * *, /TD)*
Не будет ли такое быстрее, чем построение в памяти всего DOM-дерева и исполнение на этом дереве XPath-запросов?