2011-04-20 23 views
8

este es un archivo de x original, ya que viene de m banco (no se preocupe, no hay nada sensible, corté la parte media de todas las transacciones)Cómo analizar este archivo OFX?

abierto Financial Exchange (OFX) es un Data- formato de flujo para intercambiar información financiera que evolucionó de Open Financial Conectividad de Microsoft (OFC) e Intuit Intercambiar formatos de archivo.

ahora necesito analizar esto. Ya vi ese question, pero esto no es un duplicado porque estoy interesado en cómo hacer esto.

estoy seguro de que podría descifrar algunas expresiones regulares inteligentes que harían el trabajo, pero eso es feo y vulnerable al error (si se cambia el formato, algunos campos pueden faltar, el formato/espacios en blanco son diferentes, etc. ..)

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> 

i actualmente utilizar el código que me da el resultado deseado:

<? 

$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); 

esto es realmente feo y si se trataba de un archivo XML válido i personalmente matar a mí mismo por eso, pero ¿cómo hacerlo mejor?

+3

Chico, este formato * apesta * Me sorprende que aún no se haya presentado en thedailywtf. –

+0

apuesto a que tienen guías internas en microsoft para que sea horrible para los programadores externos obtener una ventaja comercial: D –

+2

incluyendo hojas de evaluación interna: ¿Cuántas normas violaste hoy? ¿Cuántos formatos externos usó mal? ¿Cuántos programas abiertos robó para venderlos como propios? –

Respuesta

4

Su código parece correcto, teniendo en cuenta que el archivo no es XML o incluso SGML . Lo único que podrías hacer es intentar crear un analizador parecido a SAX más genérico. Es decir, simplemente recorre el flujo de entrada un bloque a la vez (donde el bloque puede ser cualquier cosa, por ejemplo, una línea o simplemente una cantidad determinada de caracteres). Luego, llame a una función de devolución de llamada cada vez que encuentre un <ELEMENT>. Incluso puede llegar a ser tan imaginativo como crear una clase de analizador donde pueda registrar funciones de devolución de llamada que escuchen elementos específicos.

Será más genérico y menos "feo" (para alguna definición de "feo") pero será más código para mantener. Agradable de hacer y agradable de tener si necesita analizar mucho este formato de archivo (o en muchas variaciones diferentes). Si su código publicado es el único lugar donde hace esto, solo KISS.

+0

Sí, esa era en realidad mi primera idea, recorriendo líneas y moviendo punteros internos de acuerdo con la etiqueta de oclusión ... . Apuesto a que tienen guías internas para dificultar que los extraños obtengan una ventaja comercial: D –

+1

@Joe: en realidad, necesito corregirme. Según Wikipedia OFX es de hecho válido SGML. Por lo tanto, debería poder utilizar cualquier analizador SGML estándar para analizar estos archivos (probablemente siempre que tenga el 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); 
Cuestiones relacionadas