SOFT
BLOG
&
Логин
Имя:
Пароль:

Internet Tools - библиотека инструментов для парсинга

Автором является господин Бенито (контактные данные на его сайте). Кроме этой библиотеки, на его сайте Вы сможете найти еще много полезных инструментов для Фрипаскаль. На самом деле заголовок не совсем точно отображает назначение библиотеки Internet Tools, это набор кода для XPath2/XQuery/JSONiq процессоров, "pattern matcher" - шаблонный сопоставитель (простой и мощный инструмент парсинга), инструменты для работы с HTML и XML подобно DOM-инструменту. А также инструменты для работы с HTTP/HTTPS, FTP протоколами.

Автор регулярно осуществляет обновление проекта, в нем исправляются ошибки и добавляются новые инструменты. Не буду приводить полное описание функций и процедур, осуществлять перевод документации.

Это очень здорово, если у Вас есть опыт работы с другими инструментами (XML, XPath, DOM, Regex). Возможно откроете для себя новый и весьма прогрессивный инструмент.

В начале я приведу адрес онлайн-инструмента Xidel, где можно применить примеры из этой статьи. Вы можете скачать Xidel для командной строки. Скачайте файл-архив, здесь вы найдете последнию версию библиотеки, файлы документации (на английском), а в папке Examples есть несколько программ в качестве примера. Среди них особо выделяется файл htmlparserExampleGUI. Это локальная почти полная версия инструмента Xidel.

htmlparserExampleGUI
Вид программы

htmlparserExampleGUI имеет 3 рабочих окна, где поля сверху-вниз:

  1. Поле запроса
  2. Поле документа (HTML/XML)
  3. Поле результатов

панель инструментов
Панель инструментов

В программе есть необходимые настройки для включения, либо отключения некоторых функций. Работает программа в 3-х режимах (кнопки управления): Template, Xpath, XQuery. Последние два, вероятно, Вам известны. Template это шаблонный сопоставитель (pattern matcher).

<html><body>
<table id="wrong">
<tr><td>Hallo</td></tr>
</table>
<table id="right">
<tr><td>123</td><td>other</td></tr>
<tr><td>foo</td><td>columns</td></tr>
<tr><td>bar</td><td>are</td></tr>
<tr><td>xyz</td><td>ignored</td></tr>
</table>
</html>

В htmlparserExampleGUI в качестве примера уже приведен template-запрос и html-документ. Хочу обратить Ваше внимание, что в html-документе, намеренно создана ошибка: тэг body не имеет закрывающего тэга (</body>). Это сделано для того, чтобы продемонстрировать как "безопасно" Internet Tools относится к ошибкам в документе и корректно обрабатывает документ. Это преимущество, т.к. html-документы очень часто имеют подобные ошибки и не все XML-процессоры способны обработать такие документы.

После описания инструментов, рассмотрим описание полей в программе. HTML и XML документы обрабатывают для выделения из всего документа только конкретной информации. Далее вместо выражения обработка, я использую слово парсинг. Создается некий запрос и он применяется к необходимому Вам документу. В результате Вы получаете некую информацию, она может быть как конечной (получение необходимого значения), либо промежуточной (какая-либо последовательность содержащее необходимое значение) для следующей обработки. В первом поле программы указывается запрос, во-втором поле Вы указываете документ, в третьем поле после обработки htmlparserExampleGUI покажет результат применения запроса. Если запрос неверен (составлен не правильно, с ошибками в синтаксисе запроса), то программа выдаст сообщение об ошибке. Результатом парсинга могут быть какие-либо значения, либо результат может быть пуст (например, подходящие значения не найдены). Библиотека возращает результат парсинга, либо в виде "плоской" последовательности, либо последовательность может быть вложена в другую последовательность, т.е. результат может быть иерархичным.

Стоит остановится и в начале внимательно изучить программу htmlparserExampleGUI или онлайн-инструмент Xidel для того чтобы понять все преимущества Internet Tools. Также эти инструменты Вы сможете применять для отладки Ваших запросов. Забегая вперед, хочу обратить внимание что библиотека весьма легко подключается к Вашему проекту и требуется небольшая инциализация библиотеки. После парсинга остается лишь обработать результат-последовательность. Далее Вы можете сохранить данные, например в новый файл, Базу Данных и т.д.

 

XPath-режим

XPath очень популярен и не сложный инструмент в парсинге. Поддержка этого языка есть во многих языках программирования (Паскаль, С, PHP, JAVA), часто применяется при работе с путями в объектной модели документа (DOM). У него простой синтаксис запросов. Есть много различных программ-инструментов, которые обрабатывают XPath. Например, в браузере Mozilla Firefox есть дополнение FirePath - это XPath процессор. Библиотека Internet Tools почти польностью поддерживает XPath версии 2. К сожалению мне не известно, что именно библиотека не поддерживает. Все мои XPath-запросы библиотека обрабатывала правильно, у меня не возникало проблем в этом режиме. Библиотека правильно выполняет простые запросы и "популярные" XPath-функции.

Также она правильно работает с Осями (AxisName) в XPath выражениях. Например, если применить следующее выражение к стандартному документу, который в программе записан в качестве примера:

Выражение XPath: descendant::tr/*

Ответ программы: sequence: (node: Hallo, node: 123, node: other, node: foo, node: columns, node: bar, node: are, node: xyz, node: ignored)

Данный запрос состоит из относительного маршрута, в контексте элемента tr ось descendant выбирает дочерние узлы.  Есть иное выражение с более коротким видом, но уже с абсолютным маршрутом и с таким же результатом: //tr/*. Если в дочерних узлах существуют следующие узлы, то отдельно они не обрабатываются. При необходимости обработать все отдельные элементы как текстовые узлы, то запрос должен иметь вид descendant::tr//text() или //tr//text().

Следующий более сложный пример с функциями XPath:

Выражение XPath:  //tr[position()<3]/* | //tr[last()]

Ответ программы: sequence: (node: Hallo, node: Hallo, node: 123, node: other, node: foo, node: columns, node: xyzignored)

Запрос выбирает все узлы элемента tr, которые имеет позицию менее 3-х или является последним элементом. Это сложный запрос состоит из двух подзапросов объединенные логическим оператором | (или), каждый из которых обрабатывается отдельно. Так как узел Halo является и нодой и текстом, то результат выводится 2 раза. Последний узел xyzignored не состоит из двух отдельных узлов, так как в данном подзапросе XPath не "обходит" дочерние узлы.

Выражение XPath: //tr//node()

Ответ программы: sequence: (node: Hallo, node: Hallo, node: 123, node: 123, node: other, node: other, node: foo, node: foo, node: columns, node: columns, node: bar, node: bar, node: are, node: are, node: xyz, node: xyz, node: ignored, node: ignored)

Это выражение выбирает все текущие узлы. Все узлы продублированы это произошло потому, что в данном контексте каждый узел является одновременно как узлом элемента (<td>Halo</td>), а далее node() выводит и текстовый узел Halo.

Выражение для работы с атрибутами элементов:

Выражение XPath: //@*

Ответ программы: sequence: (node: wrong, node: right)

Запрос найдет и отобразит все атрибуты из всех элементов в документе.

Обратите внимание результатом работы всегда является текст. Для того чтобы парсер выводил элементы, в настройках необходимо отключить режим text only.

В ответе программы слова sequence:() и node: выводятся самой программой, для того чтобы обозначить последовательности и узлы. Специфика парсинга — это результат, в котором  выдаются только данные.

Под выражением специфика парсинга, имею ввиду действия для получения текствых данных. Данную специфику никто не определяет, каждый для себя сам решает как обработать данные и в каком представлении эту информацию получить.

 

Template-режим

В документации по данному режиму есть различная информация. Автором классифицируется как High-Level, самый мощный инструмент для парсинга.

Виды запросов

Есть несколько видов синтаксиса для парсинга: обычный, упрощенный и короткий. Запросы должны соответствовать стандартам XML, могут храниться внутри XML-документов, могут быть применены к любому XML и HTML документу. Особая черта template-запросов это возможность использования внутри обычных XPath-выражений (комбинированный режим).

Обычная форма запроса:

Запрос: <b><template:read var="test" source="text()" /></b>
Html-файл: <b>Hello World!</b>
Ответ программы: test=node: Hello World!

Запрос представляет собой набор из тэгов с управляющим тэгом из пространства имён template:. Назовем данный тэг - тэгом запроса. В данном запросе тэг template:read осуществляет поиск текстовых данных в рамках тэга b и присваивает результат переменной test. Также обратите внимание, тэг запроса закрыт, имеет косую черту в конце тэга. Поиск данных производится в пределах тэга b, в данном запросе поиск производится без рекурсии. Запрос source="text()" это форма XPath-выражения.

Вариант записи:

Запрос: <b><t:s>test:=text()</t:s></b>

Это тот же запрос, что и в предыдущем примере. Тэг запроса t:s это упрощенный вариант template:read. Переменная указывается как обычное символьное имя, далее знак присвоения := (как в Паскале), и команда XPath text().

Запрос: <b>{test:=text()}</b>

В данном варианте использован самый короткий вид запроса. Вместо тэгов <t:s></t:s> используется фигурные скобки { }.

Описав особенности запроса, хочу заметить что, использование переменной test вовсе не обязательно. В несложных запросах переменные можно не использовать. Например, этот же запрос может выглядеть как <b>{text()}</b>.

Template команды

  • template:read - команда чтения данных, тэг требует наличие одного соответствия
  • template:loop - команда чтения данных, при этом данные могут иметь 0 и более совпадений
  • template:if и template:else - команды чтения данных по условию, не часто применяется, так как те же условия можно задать в XPath части запроса
  • template:switch - команда чтения данных, команда завершает работу после чтения данных, которые совпали в одном из перечисленных условии. template:switch-prioritized та же команда, но с использованием приоритетов в условии
  • template:match-text - команда чтение данных, которые соответствуют определенным критериям ([regex=".."] [starts-with=".."] [ends-with=".."] [contains=".."] [is=".."] [case-sensitive=".."] [list-contains=".."])
  • template:meta - команда чтения данных, которые соответсвуют 2-м критериям. Это метод сравнения текста и использование чувствительности к регистру текста

Есть еще вспомогательные атрибуты:

  • template:optional="true" - применяется в отношении тэгов, указывает является ли наличие тэга обязательным. Например <a template:optional="true">123</a> - при запросе этот тэг с текстом 123 не является обязательным
  • template:condition="xpath" - применяется к тэгу который соответствует XPath-выражению

Особенности режима Template

Как работает данный режим достаточно легко понять на примерах. Сами запросы как вид XML легко запоминаются. Для следующих примеров будет применен короткий и длинный вид запросов с использованием XPath-выражений.

Откроем программу htmlparserexamplegui. В него по-умолчанию записан пример template-запроса:

<table id="right">
<template:loop>
<tr><td>{col:=text()}</td></tr>
</template:loop>
</table>

И HTML-документ:

<html><body>
<table id="wrong">
<tr><td>Hallo</td></tr>
</table>
<table id="right">
<tr><td>123</td><td>other</td></tr>
<tr><td>foo</td><td>columns</td></tr>
<tr><td>bar</td><td>are</td></tr>
<tr><td>xyz</td><td>ignored</td></tr>
</table>
</html>

Результатом работы запроса будет выбор текстовых данных из первого столбца таблицы с идентификатором right. Команда template:loop обрабатывает все совпадающие условию <tr><td>{col:=text()}</td></tr> строки таблицы. Так как, указан один тэг td, то условию подпадают первые тэги в строках tr.

Рассмотрим запрос:

<table id="right">
<template:loop>
<tr>{td[last()]/text()}</tr>
</template:loop>
</table>

Данный запрос модифицирован, он осуществляет выбор данных из последнего тэга td  в строке tr. Пока запрос достаточно сложно выглядит и ввиде XPath-выражения он гораздо проще: //table[@id="right"]//td[last()]/text()

Следующий запрос:

<template:loop>
<table id="wrong" />
<td>{text()}</td>
</template:loop>

Результат запроса будет текст: 123 - это данные из первого тэга td таблицы с идентификатором right. При этом запрос не учитывает какая вложенность у тэга td. Тэг <table id="wrong" /> в запросе указывает что в HTML-документе перед искомым td тэгом обязательно должна присутствовать таблица с идентификатором wrong. Например, если из искомого документа удалить таблицу wrong (или данный идентификатор), то данный запрос вернёт пустой результат. В отличие от XPath-выражений в template-запросах нет Осей (AxisName), т.е. обрабатываются все тэги со всеми их уровнями вложенности в документе. Но определяются данные, которые находятся выше и ниже искомых данных. Команда template:loop указывает, что искомые данные могут быть в документе, либо отсутствовать. Если не указать данную команду, то запрос требует обязательное наличие хотя бы одного совпадения, иначе программа вызовет исключение.

XML-документ:

<a><aa><aaa><aaaa>notkey</aaaa></aaa></aa></a>
<b>KEY1</b>
<c>KEY2</c>

Запрос:

<template:loop>
notkey
<c>{text()}</c>
</template:loop>

Запрос осуществит выбор данных из тэга с только в том случае, если над этим тэгом встречается хотя бы одно слово notkey, при этом не важно находится ли оно внутри тэга(ов). Такое поведение подобно при использовании выражений REGEX, но с более легким синтаксисом и поддержкой XPath.

Следующий запрос демонстрирует последовательность в обработке данных:

<template:loop>
<b>{text()}</b>
<c>{text()}</c>
</template:loop>

Этот запрос выполнится в том случае, если тэг b будет выше тэга с.

Используя преимущества Template-режима возможно создавать сложные запросы со сложными условиями с интуитивно-понятным синтаксисом.

В следующем документе данного раздела, я постараюсь привести интересные и реальные примеры использования бибилиотеки Internet Tools. В текущем документе не был описан режим XQuery, но как понятно из названия, он предназначен для обработки данных с использованием XQuery-шаблонов.

Ссылки примеров с этой библиотекой: