Пакет для парсинга XML-отчётов брокера Атон (формат BIS:BISPeriod) в удобную структуру данных, чтобы в проекте можно было:
- передать путь до XML-файла,
- получить объект отчёта (
Report), - быстро выбрать нужный блок (
Trades,MoneyInOut,StockInOut, …), - найти операцию по
OperID, - собрать список всех
OperID(например, для сверки с БД), - работать с атрибутами строк через удобные геттеры (строки/даты/числа) без «магических» индексов массива.
Цель: минимальная боль при работе с реальными отчётами (namespaces, windows-1251, разные форматы дат, дробные числа).
use MasyaSmv\AtonStatementParser\AtonStatementParser;
$report = AtonStatementParser::fromFile('/path/to/report.xml');
// Доступ к секциям (универсально)
$trades = $report->section('Trades')->rows(); // Row[]
$money = $report->section('MoneyInOut')->rows(); // Row[]
// Поиск по OperID
$row = $report->findOperId('567890123'); // Row|null
// Список всех OperID (для сверки)
$ids = $report->operIds(); // array<int|string>
// Удобные геттеры атрибутов
$type = $report->section('Trades')->rows()[0]->getString('TradeType');
$date = $report->section('Trades')->rows()[0]->getDate('OperDateSort'); // DateTimeImmutable|nullXML использует xmlns:BIS=..., значит нельзя просто «по имени тега» — нужен XPath с корректной регистрацией namespace.
В шапке отчёта встречается encoding="windows-1251". Пакет должен безопасно перевести документ в UTF-8 перед парсингом.
В отчётах встречаются:
29.12.202302.10.2416.11.1826.12.24 /(мусорные хвосты)
Нужен нормализатор даты: трим + поддержка d.m.Y и d.m.y.
Количество и суммы — строки с точностью (100000.00000000). Базовый слой хранит как string, а геттеры умеют приводить к float/int при необходимости.
- Report — весь отчёт, доступ к секциям и общим данным.
- Section — один блок внутри отчёта (например
Trades,MoneyInOut). - Row — одна строка
<BIS:Row .../>внутри секции. Хранит атрибуты + типовые геттеры.
- Базовый (универсальный):
Report/Section/Row— работает для любых секций без генерации десятков DTO. - Продвинутый (DTO для популярных секций):
TradeDto,MoneyInOutDtoи т.п. — добавляются постепенно, когда станет понятно, что реально часто используется.
src/
AtonStatementParser.php // fromFile/fromString
Report/
Report.php // секции + commonData
Section.php // имя секции + Row[]
Row.php // атрибуты BIS:Row + геттеры
Xml/
XmlLoader.php // чтение файла, encoding -> utf8, DOM
XPathFactory.php // DOMXPath + регистрация namespace
Normalizers/
DateNormalizer.php // даты (d.m.y / d.m.Y, мусорные хвосты)
NumberNormalizer.php // числа/десятичные строки
StringNormalizer.php // trim/cleanup
Exceptions/
ParseException.php
InvalidXmlException.php
tests/
Fixtures/
aton/
...xml
...
- Базовый каркас пакета (autoload, структура, базовые тесты)
- Fixtures подключены в тесты
- Composer scripts:
test,cs:*,stan
-
AtonStatementParser::fromFile(string $path): Report -
AtonStatementParser::fromString(string $xml): Report -
Report->section(string $name): Section -
Section->rows(): array<Row> -
Report->operIds(): array(собратьOperIDпо секциям) -
Report->findOperId(string $id): ?Row - Unit-тесты на fixtures (operIds/findOperId/section)
-
Row->getString($key) -
Row->getInt($key) -
Row->getFloat($key) -
Row->getDecimalString($key)(без потери точности) -
Row->getBool($key) -
Row->getDate($key): ?DateTimeImmutable - Поддержка форматов дат/времени из реальных отчётов:
-
dd.mm.yy→ расширение доdd.mm.yyyy -
OperDateSort="dd.mm.yyyy 0:00:00"(время всегда 00:00:00) -
OperTimeSort="01.01.1900 HH:ii:ss"(дата фиксированная, важно время) - значения вида
26.12.24 /(чистка мусора) - стабильный парсинг даты без “текущего времени” (через
!в форматах)
-
- Тесты на даты/числа + реалистичный fixture
-
Row->getStringRequired()/getIntRequired()/getDecimalStringRequired()/getDateRequired()(кидают исключение с контекстом) - Доменные “обёртки” по секциям:
-
TradeRow(секцияTrades) -
MoneyInOutRow(секцияMoneyInOut) -
StockInOutRow(секцияStockInOut) -
ClientMoneyConvertRow(секцияClientMoneyConvert)
-
- Сахар на уровне
Report/Section:-
Report->trades(): array<TradeRow>(илиsection('Trades')->asTrades()) -
Report->moneyInOut(): array<MoneyInOutRow>
-
- Тесты доменных секций
-
TradeDto,MoneyInOutDto(минимальный набор полей, нужный проекту) - Мапперы секций → DTO (через доменные row-обёртки)
- Тесты DTO-маппинга (валидные/невалидные строки, обязательные поля)
- Фильтрация/поиск по секции:
-
section()->filter(fn(Row $r) => ...) -
section()->firstWhere(...)
-
- Индексация по
OperID(лениво или при первом вызове) - Улучшение ошибок парсинга (контекст: секция, ключ, значение)
- (Опционально) оптимизация под большие XML (если реально потребуется)
- В репозиторий коммитим только обезличенные XML.
- Реальные отчёты для локальной отладки — держать в
tests/FixturesLocal/(и добавить в.gitignore).
Рекомендуется добавить .gitattributes, чтобы не ловить «невидимые» правки концов строк (LF/CRLF).
composer require masyasmv/aton-statement-parsercomposer install
composer test
composer cs:fix
composer cs:check
composer stanMIT. См. файл LICENSE.