2011-04-20 2 views
8

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

Open Financial Exchange (OFX) является данных- поток для обмена финансовая информация, которая была развита от Microsoft Open Financial Возможности подключения (OFC) и Intuit's Open Форматы файлов Exchange.

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

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

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 я бы лично убить себя за это, но как это сделать лучше?

+3

Мальчик, этот формат * воняет! * Я удивлен, что он еще не был показан на thedailywtf. –

+0

Я уверен, что у них есть внутренние ориентиры на microsoft, чтобы сделать его ужасным для внешних программистов, чтобы получить преимущество в бизнесе: D –

+2

включая внутренние оценочные листы: сколько стандартов вы нарушили сегодня? сколько внешних форматов вы неправильно использовали? сколько открытого программного обеспечения вы украли, чтобы продать, как наши собственные? –

ответ

4

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

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

+0

да, это была моя первая идея, прокручивая строки и меняя внутренние указатели в соответствии с тегом occourence .. . Я уверен, что у них есть внутренние рекомендации, чтобы затруднить получение аутсайдерами преимуществ для бизнеса: D –

+1

@Joe: На самом деле, мне нужно исправить себя. Согласно Wikipedia OFX на самом деле действителен SGML. Таким образом, вы должны иметь возможность использовать любой стандартный синтаксический анализатор SGML для анализа этих файлов (возможно, при наличии DTD). –

0
// Load Data String  
    $str = file_get_contents($fLoc); 
    $MArr = array(); // Final assembled master array 
// Fetch all transactions 
    preg_match_all("/<STMTTRN>(.*)<\/STMTTRN>/msU",$str,$m); 
    if (!empty($m[1])) { 
     $recArr = $m[1]; unset($str,$m); 
     // Parse each transaction record 
     foreach ($recArr as $i => $str) { 
      $_arr = array(); 
      preg_match_all("/(^\s*<(?'key'.*)>(?'val'.*)\s*$)/m",$str,$m); 
      foreach ($m["key"] as $i => $key) { 
       $_arr[$key] = trim($m["val"][$i]); // Reassemble array key => val 
      } 
      array_push($MArr,$_arr); 
     } 
    } 
    print_r($MArr); 
Смежные вопросы