# Получение данных из XML-потоков

Тип источника `xmlpipe2` позволяет передавать пользовательские полнотекстовые и атрибутные данные в Manticore в пользовательском XML-формате, при этом схема (т.е. набор полей и атрибутов) задаётся либо в самом XML-потоке, либо в настройках источника.

## Объявление XML-потока
Для объявления XML-потока обязательна директива `xmlpipe_command`, которая содержит shell-команду, производящую индексируемый XML-поток. Это может быть файл, но также возможно выполнение программы, которая генерирует XML-содержимое на лету.

## Формат XML-файла

При индексации источника xmlpipe2 индексатор запускает указанную команду, открывает пайп к её stdout и ожидает правильно сформированный XML-поток.

Вот пример того, как может выглядеть XML-поток данных:

```xml
<?xml version="1.0" encoding="utf-8"?>
<sphinx:docset>

<sphinx:schema>
<sphinx:field name="subject"/>
<sphinx:field name="content"/>
<sphinx:attr name="published" type="timestamp"/>
<sphinx:attr name="author_id" type="int" bits="16" default="1"/>
</sphinx:schema>

<sphinx:document id="1234">
<content>this is the main content <![CDATA[and this <cdata> entry
must be handled properly by xml parser lib]]></content>
<published>1012325463</published>
<subject>note how field/attr tags can be
in <b> class="red">randomized</b> order</subject>
<misc>some undeclared element</misc>
</sphinx:document>

<sphinx:document id="1235">
<subject>another subject</subject>
<content>here comes another document, and i am given to understand,
that in-document field order must not matter, sir</content>
<published>1012325467</published>
</sphinx:document>

<!-- ... even more sphinx:document entries here ... -->

<sphinx:killlist>
<id>1234</id>
<id>4567</id>
</sphinx:killlist>

</sphinx:docset>
```

Разрешаются произвольные поля и атрибуты. Они также могут встречаться в потоке в произвольном порядке в пределах каждого документа; порядок игнорируется. Существует ограничение на максимальную длину поля; поля длиной более 2 МБ будут обрезаны до 2 МБ (это ограничение можно изменить в источнике).

Схема, то есть полный список полей и атрибутов, должна быть объявлена до того, как можно будет разобрать любой документ. Это можно сделать либо в конфигурационном файле с помощью настроек `xmlpipe_field` и `xmlpipe_attr_XXX`, либо прямо в потоке через элемент `<sphinx:schema>`. `<sphinx:schema>` необязателен. Ему разрешено встречаться только как самый первый вложенный элемент в `<sphinx:docset>`. Если встроенного в поток определения схемы нет, будут использованы настройки из конфигурационного файла. Иначе приоритет имеют настройки потока. Обратите внимание, что идентификатор документа следует задавать как свойство `id` тега `<sphinx:document>` (например, `<sphinx:document id="1235">`). Для обычных таблиц идентификаторы документов должны быть явными, уникальными, ненулевыми беззнаковыми 64-битными целыми числами. Отрицательные идентификаторы документов не допускаются. Обычные таблицы не поддерживают автоматическую генерацию идентификаторов, и `0` нельзя использовать, чтобы запросить сгенерированный автоматически ID.

Неизвестные теги (которые не были объявлены ни как поля, ни как атрибуты) будут проигнорированы с предупреждением. В приведённом выше примере `<misc>` будет проигнорирован. Все вложенные теги и их атрибуты (например, `<strong>` внутри `<subject>`) будут тихо проигнорированы.

Поддержка кодировок входящего потока зависит от наличия установленного в системе `iconv`. xmlpipe2 анализируется с помощью парсера `libexpat`, который из коробки понимает US-ASCII, ISO-8859-1, UTF-8 и несколько вариантов UTF-16. Скрипт конфигурации Manticore также проверит наличие `libiconv` и будет использовать его для обработки других кодировок. Кроме того, `libexpat` требует использования кодировки UTF-8 на стороне Manticore, потому что возвращаемые им данные всегда находятся в UTF-8.

XML-элементы (теги), распознаваемые xmlpipe2 (и их атрибуты, где применимо):

* `sphinx:docset` — обязательный корневой элемент, обозначает и содержит набор документов xmlpipe2.
* `sphinx:schema` — необязательный элемент, должен либо встречаться как самый первый дочерний элемент sphinx:docset, либо отсутствовать совсем. Объявляет схему документа и содержит определения полей и атрибутов. Если присутствует, он переопределяет настройки источника из конфигурационного файла.
* `sphinx:field` — необязательный элемент, дочерний для sphinx:schema. Объявляет полнотекстовое поле. Известные атрибуты:
    * "name" — указывает имя XML-элемента, которое будет рассматриваться как полнотекстовое поле в последующих документах.
    * "attr" — указывает, индексировать ли это поле также как строковое. Возможное значение — "string".
* `sphinx:attr` — необязательный элемент, дочерний для sphinx:schema. Объявляет атрибут. Известные атрибуты:
    * "name" — имя элемента, который следует трактовать как атрибут в последующих документах.
    * "type" — тип атрибута. Возможные значения: "int", "bigint", "timestamp", "bool", "float", "multi" и "json".
    * "bits" — размер в битах для типа атрибута "int". Допустимые значения от 1 до 32.
    * "default" — значение по умолчанию для атрибута, которое будет использоваться, если элемент атрибута отсутствует в документе.
* `sphinx:document` - Обязательный элемент, должен быть дочерним элементом sphinx:docset. Содержит произвольные другие элементы со значениями полей и атрибутов, которые нужно индексировать, как объявлено либо с помощью элементов sphinx:field и sphinx:attr, либо в конфигурационном файле. Единственный известный атрибут — "id"; он должен содержать явный, уникальный, ненулевой беззнаковый 64-битный идентификатор документа.
* `sphinx:killlist` — необязательный элемент, дочерний для sphinx:docset. Содержит несколько элементов "id", содержимое которых — идентификаторы документов, помещаемые в "kill-list" таблицы. Kill-list используется при поисках по нескольким таблицам для подавления документов, которые найдены в других таблицах поиска.

## Определение данных в конфигурации источника

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

* `xmlpipe_field` — объявляет поле типа `text`.
* `xmlpipe_field_string` — объявляет текстовое поле/строковый атрибут. Колонка будет индексироваться как текстовое поле и одновременно храниться как строковый атрибут.
* `xmlpipe_attr_uint` — объявляет целочисленный атрибут
* `xmlpipe_attr_timestamp` — объявляет атрибут типа timestamp
* `xmlpipe_attr_bool` — объявляет булев атрибут
* `xmlpipe_attr_float` — объявляет числовой с плавающей точкой атрибут
* `xmlpipe_attr_bigint` — объявляет атрибут типа big integer
* `xmlpipe_attr_multi` — объявляет многозначный атрибут с целыми числами
* `xmlpipe_attr_multi_64` — объявляет многозначный атрибут с 64-битными целыми числами
* `xmlpipe_attr_string` — объявляет строковый атрибут
* `xmlpipe_attr_json` — объявляет атрибут в формате JSON

### Специфические настройки XML источника

Если установлена настройка `xmlpipe_fixup_utf8`, это будет включать проверку и фильтрацию UTF-8 на стороне Manticore для предотвращения сбоев XML-парсера на документах, не являющихся UTF-8. По умолчанию эта опция отключена.

В определённых случаях может быть трудно или даже невозможно гарантировать, что входящие тела документов XMLpipe2 имеют полностью корректное и соответствующее UTF-8 кодирование. Например, в поток могут проникать документы с национальными одно-байтовыми кодировками. XML-парсер libexpat является хрупким, что означает, что он прекратит обработку в таких случаях. Функция исправления UTF8 позволяет избежать этой проблемы. Когда исправление включено, Manticore будет предварительно обрабатывать входящий поток перед передачей его XML-парсеру и заменять недопустимые UTF-8 последовательности пробелами.

```ini
xmlpipe_fixup_utf8 = 1
```

Пример XML-источника без схемы в конфигурации:

```ini
source xml_test_1
{
    type = xmlpipe2
    xmlpipe_command = cat /tmp/products_today.xml
}
```

Пример XML-источника со схемой в конфигурации:

```ini
source xml_test_2
{
    type = xmlpipe2
    xmlpipe_command = cat /tmp/products_today.xml
    xmlpipe_field = subject
    xmlpipe_field = content
    xmlpipe_attr_timestamp = published
    xmlpipe_attr_uint = author_id:16
}
```
<!-- proofread -->

