«Парсер» разбирает любые текстовые структуры: HTML, XML, JSON или произвольный текст. Чаще всего его применяют для разбора ответов веб-сервисов, полученных компонентом «Запрос к WEB-сервису».
На вход подаётся документ — структура, подлежащая разбору. Задать её можно текстом, переменной, выражением или функцией. Дальше выбирается алгоритм разбора и пишется поисковый запрос; результат сохраняется в переменную.
Свойства компонента
| Свойство | Описание |
|---|---|
| Документ | Аргумент с текстовой структурой, подлежащей разбору. |
| Алгоритм | Регулярные выражения, язык OQuery для HTML, парсер JSON. |
| Поисковый запрос | Строка запроса для выбранного алгоритма. Язык регулярных выражений совпадает со стандартом .NET. |
| Функция | Что именно вернуть; набор зависит от алгоритма — см. ниже. |
| Номер элемента | Порядковый номер структуры, если запрос нашёл несколько результатов. Доступно для регулярных выражений и OQuery. |
| Атрибут | Только для OQuery и функций, связанных с атрибутами. «Значение атрибута» ждёт имя или порядковый номер атрибута, «Имя атрибута» — только порядковый номер. |
| Результат в переменную | Переменная, куда сохранится результат: число либо вырезанный или сформированный текст. |
| Переход | Куда идти при корректном выполнении запроса. |
| Переход, неудача | Куда идти при неудаче разбора. |
У регулярных выражений и парсера JSON — с 0.
Это самая частая причина того, что цикл перебора возвращает не тот элемент или промахивается на один.
Функции по алгоритмам
| Алгоритм | Доступные функции |
|---|---|
| Регулярные выражения | Содержимое; Количество найденных. |
| OQuery | Документ — текст структуры с обрамляющими тегами; Содержимое — без обрамляющих тегов; Количество элементов — число найденных структур на одном уровне; Значение атрибута; Имя атрибута; Количество атрибутов. |
| JSON | Содержимое — значение элемента, объект или массив; значение элемента возвращается в кавычках. Восстановленное содержимое — то же без кавычек. Количество элементов — число вложенных элементов, объектов, массивов. |
Язык OQuery
Запрос OQuery — это набор команд, записанный в одну строку и выполняемый слева направо. Для отладки запросов служит программа OQuery-tester.exe.
Уровни
| Знак | Что означает |
|---|---|
* | Все элементы |
> | Все дочерние элементы |
^ | Корневые элементы — на нулевом уровне искомой структуры |
| пробел | Все элементы, кроме корневых |
Простые команды
| Команда | Что делает | Пример |
|---|---|---|
| название тега | Теги; английские буквы и цифры, начинается с буквы. | ^TITLE — тег TITLE в корне |
#значение | Теги, у которых атрибут id равен указанному значению. | FORM#32 — теги FORM с id=32 |
[название=значение] | Теги, в теле которых есть атрибут с таким названием и значением. | TABLE[width=90%] |
.значение | Теги, у которых атрибут class содержит указанное значение. | INPUT.b.c — теги с class="a b c" |
Порядок перечисления команд на результат не влияет: TABLE#big.sample и TABLE.sample#big — одно и то же.
Операции сравнения значений атрибута
| Знак | Условие | Пример |
|---|---|---|
= | Полное совпадение | TABLE[width=90%] |
^= | Начинается со значения | IMG[src^="http://example.org/images"] |
$= | Заканчивается значением | IMG[src$=".gif"] |
*= | Значение содержится где-то внутри | IMG[src*="banner"] |
Суффиксы и функции позиции
| Команда | Что делает | Пример |
|---|---|---|
:first | Первый элемент коллекции | TD:first |
:last | Последний элемент коллекции | UL:last |
:parent | Родительские теги элементов коллекции | TABLE>TD>A:parent:parent |
:gt(позиция) | Элементы начиная с указанной позиции | TD:gt(10) |
:lt(позиция) | Элементы до указанной позиции включительно | TD:lt(15) |
:eq(позиция) | Элемент указанной позиции; отрицательное число отсчитывается с конца | TD:eq(-3) — третий тег с конца |
:eq(начало,конец) | Набор элементов от начальной до конечной позиции; отрицательные числа — с конца | TD:eq(-1,-3) — последние три элемента |
Синонимы eq: equal, range.
Сложные функции
| Команда | Что делает |
|---|---|
:has(запрос) | Теги, содержащие другие теги, удовлетворяющие указанному запросу. TABLE:has(^TD>A) — аналог TABLE>TD>A:parent:parent. |
:not(запрос) | Теги, не удовлетворяющие указанному запросу. A:eq(1,10):not(:eq(2)) — все теги A с первого по десятый, кроме второго. |
A:has(:not(IMG)) — все теги A, которые содержат не IMG
A:not(:has(IMG)) — все теги A, которые не содержат IMG
Результаты у этих запросов разные.
Операции и скобки
| Знак | Что делает | Пример |
|---|---|---|
, | Логическое «или» — перечисление запросов | *A>IMG,>TABLE — все IMG внутри A и все TABLE в корне |
+ | Теги по запросу 1, за которыми идут теги по запросу 2 | A + IMG + #num |
- | Теги по запросу 1, перед которыми идут теги по запросу 2 | — |
( ) | Объединение команд одинакового приоритета | (FONT,A)(:has(IMG),:has(SPAN)) |
Типовые наборы команд
| Запрос | Что вернёт |
|---|---|
^FONT | Все теги FONT корневого (нулевого) уровня |
>FONT | Все теги FONT первого уровня |
*FONT | Все теги FONT |
*>FONT | Все теги FONT, кроме корня |
*>>FONT или >*>FONT | Все теги FONT начиная со второго уровня |
A>>B | Все теги B на втором уровне у A |
Разбор XML: пример
Пусть разбирается такая структура — два листа, на первом матрица 3×3, на втором 2×2:
<info>
<list index="1" name="matrix33">
<row id="1" name="aaa">
<col id="1" name="r1c1" />
<col id="2" name="r1c2" />
<col id="3" name="r1c3" />
</row>
…
</list>
<list index="2" name="matrix22">
<row id="1" name="ddd">
<col id="1" name="element11" />
<col id="2" name="element12" />
</row>
<row id="2" name="eee">
<col id="1" name="element21" />
<col id="2" name="element22" />
</row>
</list>
</info>
| Запрос | Что вернёт |
|---|---|
info | Все теги <info> с содержимым |
list | Все теги <list> — информацию по обоим листам |
list[index="2"] | Всю информацию второго листа |
col[id="2"] | Все элементы второго столбца в обеих матрицах |
list[index="2"] col[id="2"] | Элементы второго столбца только на втором листе |
col[id="2"][name="element22"] | Один конкретный тег |
(col[id="1"]):last:parent | Родительский тег последнего <col id="1"> |
Добравшись до нужного тега, значение его атрибута берут функцией «Значение атрибута», указав имя атрибута в поле «Атрибут». Если запрос вернул несколько тегов, их перебирают в цикле через «Номер элемента», а общее число узнают функцией «Количество элементов».
Регулярные выражения
Применяются для разбора обычного текста. Язык совпадает со стандартом .NET.
?: — иначе значение не вернётся в переменную сценария.
Примеры
| Выражение | Что находит |
|---|---|
\S+ | Все целые слова |
[A-Z][A-Za-z]+ | Слова, начинающиеся с прописной буквы |
X\-Forwarded\-For\:\s*(\S+(?:[^\r\n]+\S+)*) | Всё после заголовка X-Forwarded-For: до переноса строки |
(?:[a-zA-Z0-9][a-zA-Z0-9\-\.]*@)?(?:[a-zA-Z0-9][a-zA-Z0-9\-]*\.)+[a-zA-Z]{2,999} | Адреса электронной почты и доменные имена в тексте |
X-Forwarded-For и Delivered-To в теле такого письма как раз и содержат исходный адрес получателя.
Если выражение вернуло несколько значений, их перебирают в цикле; общее число даёт функция «Количество найденных».
Парсер JSON
У платформы собственный синтаксис разбора JSON, и он предельно прост:
- доступ к значению — по имени в кавычках;
- переход к вложенному объекту — через
/; - обращение к элементу массива — по индексу, отсчёт с нуля.
Для документа вида:
{
"info": {
"list1": {
"index": 1,
"name": "matrix",
"rows": [
{ "id": 1, "name": "row1",
"cols": [ {"id":"1","name":"element11"}, {"id":"2","name":"element12"} ] },
{ "id": 2, "name": "row2",
"cols": [ {"id":"1","name":"element21"}, {"id":"2","name":"element22"} ] }
]
}
}
}
| Запрос | Результат |
|---|---|
"info"/"list1"/"name" | "matrix" |
"info"/"list1"/"rows"/1/"name" | "row2" — второй элемент массива, отсчёт с нуля |
"info"/"list1"/"rows"/1/"cols"/0/"name" | "element21" |
Функция «Содержимое» вернёт значение в кавычках, «Восстановленное содержимое» — без них. Для дальнейших сравнений в сценарии обычно нужен второй вариант.