For a site i am building right now, there is one component that I would want the user to upload a file, where it will be parsed (currently a python script, but can be ported to something else). The data from the parser will then be used populate a node.

what will be the best way to go around doing this? rules to start the parsing and feeds to import the data? a custom php page? or a custom mod to generate the display i want from the file uploaded in the same node?

need some guidance >,<

  • What kind if data is it? Should the node that is created be able to be updated with a new file upload and parsing or is it just new files? – Pontus Nilsson Jul 31 '14 at 8:41
  • the data is basic ascii text file. output from the parser will be strings and arrays. to make things simple, each upload will only create a new node, no need to modify the current one – i0rz Jul 31 '14 at 8:51

I would create a new url where files can be uploaded. This is done with a implementation of hook_menu.

If you want to use Feeds you first need to upload the file and have it converted to rss/csv/opml etc and then use Feeds to map against a node. I would go with a custom module instead so that you can create nodes straight away instead of a "two step operation".

You can find out how to create a form that handles file uploads here. In the submit function for your form you would need to programatically create nodes from the file upload. This can be done in several ways but one is by using Entity metadata wrappers, which I find easy to work with. You can find out more about that here.

This all might sound like a lot of work and I didn't suggest a contributed module but I think in your case it would be more work to first convert the data to something readable by Feeds for example.


What format is your uploaded file in? If it's something standard like csv, xml etc then I'd look at the feeds module https://www.drupal.org/project/feeds that's exactly what it's for, less chance of bugs/errors and less maintenance than building your own.

You should be able to parse non standard file types with it too, but as Pontus said you're adding an extra step.


Here is a custom rules action module that i use in a a site, it loads a XML file (mexican invoice file), parsers it and saves some data from file in a node, and returns a variable knowing if node data was saved or not in node. Take a close look how file and node are loaded in rules action, and how file is opened by uri and access it's content. Note: file was previously loaded by user and saved in a node, i'm affecting same node.

   * Implement hook_rules_action_info()
   * Declare any meta data about actions for Rules

  function procesarfactura_rules_action_info() {
    $actions = array(
      'procesar_factura_xml' => array(
          'label' => t('Procesar factura'),
          'group' => t('factura'),
          'parameter' => array(
              'file' => array(
                      'type' => 'file',
                      'label' => t('Archivo a procesar'),
              'node' => array(
                  'type' => 'node',
                  'label' => t('Nodo a procesar'),

          'provides' => array(
            'procesada' => array(
              'type' => 'integer',
              'label' => '1=procesada, 0=no procesada',
        return $actions;
  } // fin de actions_info

  // rules function procesar factura
  function procesar_factura_xml($file, $node) {
    $procesada = array();
    $procesada = 0;

    $node = node_load($node->nid);
    $nidflagged = $node->nid;

    // get $url path to load $file
    $uri = $node->field_factura_xml['und'][0]['uri'];
    // Take a look at: file.inc::file_load_multiple
    $files = file_load_multiple(array(), array('uri' => $uri));
    $file = reset($files); // If empty, $file will be false, otherwise will contain the required file

     $xml = null;
     $xml = simplexml_load_file($uri);

     //si no pudo subir la factura, mostrar error, unflag node
  if(!$xml) {
    drupal_set_message('Su archivo XML no fue cargado correctamante, favor de intentar nuevamente.', 'status', FALSE);
    drupal_set_message('Nota: despues de subir el archivo al servidor, haga clic en el nombre de su archivo,
    si se muestra en pantalla, ya esta cargado correctamente, navege hacia atras su navegador y procese su factura.', 'status', FALSE);

    $flag = flag_get_flag('flag_nodo_factura_cliente');
      if ($flag) {
        // Unflag node
        $flag->flag('unflag', $nidflagged);
  else {

    $ns = $xml->getNamespaces(true);
    $xml->registerXPathNamespace('c', $ns['cfdi']);
    $xml->registerXPathNamespace('t', $ns['tfd']);

    foreach ($xml->xpath('//cfdi:Comprobante') as $cfdiComprobante){

       $version =  $cfdiComprobante['Version'];
       $fechaemision =  $cfdiComprobante['Fecha'];
       $total =  $cfdiComprobante['Total'];
       $subtotal =  $cfdiComprobante['SubTotal'];
       $formadepago =  $cfdiComprobante['FormaPago'];
       $tipocomprobante =  $cfdiComprobante['TipoDeComprobante'];
       $numerocertificado = $cfdiComprobante['NoCertificado'];
       $metododepago =  $cfdiComprobante['MetodoPago'];

       //set $node field COMROBANTE values
       $node->field_factura_version['und'][0]['value'] = $version;
       $node->field_factura_fecha_de_emision['und'][0]['value'] = $fechaemision;
       $node->field_factura_total['und'][0]['value'] = $total;
       $node->field_factura_subtotal['und'][0]['value'] = $subtotal;
       $node->field_factura_forma_de_pago['und'][0]['value'] = $formadepago;
       $node->field_factura_metodo_de_pago['und'][0]['value'] = $metododepago;
       $node->field_fact_tipo_de_comprobante['und'][0]['value'] = $tipocomprobante;
       $node->field_factu_num_de_certificado['und'][0]['value'] = $numerocertificado;

       // calculo de impuestos trasladados
       $impuestostrasladados = $node->field_factura_total['und'][0]['value'] - $node->field_factura_subtotal['und'][0]['value'];
       $node->field_factura_impuestos_traslada['und'][0]['value'] = $impuestostrasladados;


      foreach ($xml->xpath('//cfdi:Comprobante//cfdi:Emisor') as $Emisor){

        $emisorrfc = $Emisor['Rfc'];
        $emisornombre =  $Emisor['Nombre'];
        //$usocfdi = $Emisor['UsoCFDI'];
        $regimenfiscal = $Emisor['RegimenFiscal'];

        $node->field_factura_rfc_emisor['und'][0]['value'] = $emisorrfc;
        $node->field_factura_emisor_nombre['und'][0]['value'] = $emisornombre;
        //$node->field_factura_uso_cfdi['und'][0]['value'] = $usocfdi;
        $node->field_fact_emisor_regimen_fiscal['und'][0]['value'] = $regimenfiscal;

      foreach ($xml->xpath('//cfdi:Comprobante//cfdi:Receptor') as $Receptor){
      $receptorrfc = $Receptor['Rfc'];
      $receptornombre =  $Receptor['Nombre'];
      $usocfdi = $Receptor['UsoCFDI'];

        $node->field_factura_receptor_rfc['und'][0]['value'] = $receptorrfc;
        $node->field_factura_receptor_nombre['und'][0]['value'] = $receptornombre;
        $node->field_factura_uso_cfdi['und'][0]['value'] = $usocfdi;

        if ($tipocomprobante == 'E' || $tipocomprobante == 'T' || $tipocomprobante == 'N') {
          # code...
          $procesada = 0;
          drupal_set_message('El documento que intenta procesar es invalido', 'error', FALSE);
          //drupal_set_message('tipo :' . $tipocomprobante .'procesada: ' .$procesada, 'warning', FALSE);

        } else {
        $procesada = 1;

      } // fin del else tipo de comprobante
      return array(
        'procesada' => $procesada,

  } // fin de funcion rules procesar_factura_xml

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.