Как разобрать этот файл OFX?

это оригинальный файл из м банка (не беспокойтесь, там нет ничего секретного, я вырезал среднюю часть со всеми транзакциями)

Open Financial Exchange (OFX) — это формат потока данных для обмена финансовой информацией, возникший на основе форматов файлов Microsoft Open Financial Connectivity (OFC) и Intuit Open Exchange.

теперь мне нужно разобрать это. я уже видел этот вопрос, но это не дубликат, потому что мне интересно, как это сделать.

я уверен, что мог бы найти несколько умных регулярных выражений, которые выполняли бы эту работу, но это уродливо и уязвимо для ошибок (если формат изменен, некоторые поля могут отсутствовать, форматирование/пробелы разные и т. д. и т. д...)

OFXHEADER:100
DATA:OFXSGML
VERSION:102
SECURITY:NONE
ENCODING:USASCII
CHARSET:1252
COMPRESSION:NONE
OLDFILEUID:NONE
NEWFILEUID:NONE
<OFX>
    <SIGNONMSGSRSV1>
        <SONRS>
            <STATUS>
                <CODE>0
                <SEVERITY>INFO
            </STATUS>
            <DTSERVER>20110420000000[+1:CET]
            <LANGUAGE>ENG
        </SONRS>
    </SIGNONMSGSRSV1>
    <BANKMSGSRSV1>
        <STMTTRNRS>
            <TRNUID>1
            <STATUS>
                <CODE>0
                <SEVERITY>INFO
            </STATUS>
            <STMTRS>
                <CURDEF>EUR
                <BANKACCTFROM>
                    <BANKID>20404
                    <ACCTID>02608983629
                    <ACCTTYPE>CHECKING
                </BANKACCTFROM>
                    <BANKTRANLIST>
                    <DTSTART>20110207
                    <DTEND>20110419
                    <STMTTRN>
                        <TRNTYPE>XFER
                        <DTPOSTED>20110205000000[+1:CET]
                        <TRNAMT>-6.12
                        <FITID>C74BD430D5FF2521
                        <NAME>unbekannt
                        <MEMO>BILLA DANKT  1265P K2 05.02.UM 17.49 
                    </STMTTRN>
                    <STMTTRN>
                        <TRNTYPE>XFER
                        <DTPOSTED>20110207000000[+1:CET]
                        <TRNAMT>-10.00
                        <FITID>C74BE0F90A657901
                        <NAME>unbekannt
                        <MEMO>AUTOMAT  13177 KARTE2 07.02.UM 10:22 
                    </STMTTRN>
............................. goes on like this ........................
                    <STMTTRN>
                        <TRNTYPE>XFER
                        <DTPOSTED>20110418000000[+1:CET]
                        <TRNAMT>-9.45
                        <FITID>C7A5071492D14D29
                        <NAME>unbekannt
                        <MEMO>HOFER DANKT  0408P K2 18.04.UM 18.47 
                    </STMTTRN>
                </BANKTRANLIST>
                <LEDGERBAL>
                    <BALAMT>1992.29
                    <DTASOF>20110420000000[+1:CET]
                </LEDGERBAL>
            </STMTRS>
        </STMTTRNRS>
    </BANKMSGSRSV1>
</OFX>

в настоящее время я использую этот код, который дает мне желаемый результат:

<?

$files = array();
$files[] = '***_2011001.ofx';
$files[] = '***_2011002.ofx';
$files[] = '***_2011003.ofx';

system('touch file.csv && chmod 777 file.csv');
$fp = fopen('file.csv', 'w');

foreach($files as $file) {
    echo $file."...\n";
    $content = file_get_contents($file);

    $content = str_replace("\n","",$content);
    $content = str_replace(" ","",$content);

    $regex = '|<STMTTRN><TRNTYPE>(.+?)<DTPOSTED>(.+?)<TRNAMT>(.+?)<FITID>(.+?)<NAME>(.+?)<MEMO>(.+?)</STMTTRN>|';


    echo preg_match_all($regex,$content,$matches,PREG_SET_ORDER)." matches... \n";


    foreach($matches as $match) {
        echo ".";
        array_shift($match);
        fputcsv($fp, $match);
    }
    echo "\n";
}
echo "done.\n";
fclose($fp);

это действительно уродливо, и если бы это был действительный файл xml, я бы лично убил себя за это, но как сделать это лучше?


person The Surrican    schedule 20.04.2011    source источник
comment
Боже, этот формат вонючий! Я удивлен, что его еще не показали на thedailywtf.   -  person Pekka    schedule 20.04.2011
comment
Бьюсь об заклад, у них есть внутренние правила в Microsoft, чтобы внешние программисты не могли получить преимущество в бизнесе: D   -  person The Surrican    schedule 20.04.2011
comment
включая листы внутренней оценки: сколько стандартов вы сегодня нарушили? сколько внешних форматов вы неправильно использовали? сколько открытого программного обеспечения вы украли, чтобы продать как наше собственное?   -  person The Surrican    schedule 20.04.2011
comment
@Pekka: это уже было на TDWTF: img.thedailywtf.com/images/201110/banksod .png   -  person Marek    schedule 02.11.2011


Ответы (1)


Ваш код выглядит нормально, учитывая, что файл не является XML или даже SGML. Единственное, что вы можете сделать, это попытаться создать более общий анализатор, подобный SAX. То есть вы просто просматриваете входной поток по одному блоку за раз (где блок может быть чем угодно, например, строкой или просто заданным количеством символов). Затем вызывайте функцию обратного вызова каждый раз, когда сталкиваетесь с <ELEMENT>. Вы даже можете пойти на хитрость, создав класс синтаксического анализатора, в котором вы можете зарегистрировать функции обратного вызова, которые прослушивают определенные элементы.

Он будет более общим и менее «уродливым» (для некоторого определения «уродливого»), но будет содержать больше кода для поддержки. Приятно делать и приятно иметь, если вам нужно много разбирать этот формат файла (или во многих разных вариациях). Если ваш опубликованный код — единственное место, где вы делаете это, просто KISS.

person Sander Marechal    schedule 20.04.2011
comment
да, на самом деле это была моя первая идея, зацикливаться на строках и сдвигать внутренние указатели в соответствии с появлением тега ... держу пари, у них есть внутренние правила, чтобы посторонним было трудно получить бизнес-преимущество: D - person The Surrican; 20.04.2011
comment
@Joe: на самом деле, мне нужно исправиться. Согласно Википедии, OFX на самом деле является действительным SGML. Таким образом, вы должны иметь возможность использовать любой стандартный анализатор SGML для анализа этих файлов (вероятно, при условии, что у вас есть DTD). - person Sander Marechal; 20.04.2011