de XML a Hash

27 views
Skip to first unread message

José Santos Arias Vega

unread,
Jun 9, 2025, 5:48:56 PMJun 9
to oo...@googlegroups.com, harbourm...@googlegroups.com
Buenas tardes compañeros.

En un foro que tiene Rafa Carmona (The Full), compartió una rutina para traspasar archivos xml a hash, esto es muy útil sobre todo para factura electrónica.

Con unos pequeños cambios para acomodarla al sistema de facturación de Chile, les comparto esta pequeña rutina, se puede adaptar a la realidad de cada país.

Se puede mejorar, claro que sí, si hay mejoras favor las comparten, los comentarios y sugerencias también son bienvenidos.


Saludos.


José Arias Vega

******************************************************************************************
* XMLTOHASH Function que convierte un archivo xml en un Hash
* Creditos Rafa Carmona (The Full)
*
*
******************************************************************************************

Function Main(cArchivo)   //Recibe el nombre del archivo XML a procesar
Local aXml,hXml,aDetalle,nHandle
aDetalle:={}
aXml:=Test(cArchivo)   // Acá revisamos el xml y extraemos todos los nodos
hXml:=aXml ["Detalle"]    // Sacamos la información de aXml solo lo que necesitamos (en este caso el detalle de la factura electrónica)
nHandle := FCreate( "Detalle.txt" )    //Para pruebas
for i=1 to len(hXml)
    aadd(aDetalle,{hXml [i] ["NroLinDet"],hXml [i] ["NmbItem"],hXml [i] ["DscItem"],hXml [i] ["QtyItem"],hXml [i] ["UnmdItem"],hXml [i] ["PrcItem"],hXml [i] ["MontoItem"]})                      FWrite( nHandle, "Linea Detalle: "+hXml [i] ["NroLinDet"]+ chr(13) + chr(10) )
    FWrite( nHandle, "Nombre Producto: "+hXml [i] ["NmbItem"]+ chr(13) + chr(10) )
    FWrite( nHandle, "Cantidad: "+hXml [i] ["QtyItem"]+ chr(13) + chr(10) )
    FWrite( nHandle, "Presentacion: "+hXml [i] ["UnmdItem"]+ chr(13) + chr(10) )
    FWrite( nHandle, "Precio Unitario: "+hXml [i] ["PrcItem"]+ chr(13) + chr(10) )
    FWrite( nHandle, "Precio Total: "+hXml [i] ["MontoItem"]+ chr(13) + chr(10) )
Next
FCLOSE(nHandle)
Return

FUNCTION Test( file )
   LOCAL pRoot, hHash, cFile
   
   IF !hb_FileExists(file)
      RETURN {=>}
   ENDIF
   
   BEGIN SEQUENCE WITH {|oErr| Break(oErr) }
      cFile := hb_MemoRead(file)
      pRoot := mxmlLoadString(NIL, cFile, MXML_OPAQUE_CALLBACK)
      hHash := XMLtoHash(pRoot, "Documento")     // Se rescatará toda la informacion del Nodo "Documento" de la factura electronica
      
      mxmlDelete(pRoot)
   RECOVER
      hHash := {=>}
   END SEQUENCE
   
   RETURN hHash

STATIC FUNCTION type_cb( node )
RETURN MXML_OPAQUE
 

// ---------------------------------------------------------------------------//
FUNCTION XMLtoHash( pRoot, cElement )
   Local pNode, hNext
   Local Map := {=>}

   if empty( cElement )
      pNode := pRoot
   else  
      pNode := mxmlFindElement( pRoot, pRoot, cElement, NIL, NIL, MXML_DESCEND )
   endif
     
   IF Empty( pNode )
      RETURN Map
   ENDIF

   hNext := mxmlWalkNext( pNode, pNode, MXML_DESCEND )
   Map :=  NodeToHash( hNext )

  return Map



STATIC FUNCTION NodeToHash( node  )
   Local hNext
   Local hHashChild := {=>}
   Local hHash := {=>}

   WHILE node != NIL
         
         IF mxmlGetType( node ) == MXML_ELEMENT

            if HB_HHASKEY( hHash, mxmlGetElement( node ) )
               if valtype( hHash[ mxmlGetElement( node ) ] ) <> "A"
                  hHash[ mxmlGetElement( node ) ] := mxmlGetOpaque( node )
               else
                 // Es un array, por lo tanto, no lo tocamos
               endif  
            else                  
               hHash[ mxmlGetElement( node ) ] :=  mxmlGetOpaque( node )
            endif  

            if empty( mxmlGetOpaque( node ) ) // Miramos dentro
               hNext := mxmlWalkNext( node, node, MXML_DESCEND )  
               if hNext != NIL
                  hHashChild :=  NodeToHash( hNext  )
                  // Correcion de Posible bug. Un elemento con espacios en blanco, deja descender un nivel!, cuando no debería!
                  // example  <element> </element>
                  if hHashChild != NIL .and. !empty( hHashChild )
                     if empty( hHash[ mxmlGetElement( node ) ] )
                        hHash[ mxmlGetElement( node ) ] := {}
                     endif  

                     if HB_MXMLGETATTRSCOUNT( node ) > 0
                        hHashChild[ mxmlGetElement( node ) + "@attr"] := HB_MXMLGETATTRS( node )
                      endif  
                      AADD( hHash[ mxmlGetElement( node ) ], hHashChild )
                  endif  

               endif  
            else  
               if HB_MXMLGETATTRSCOUNT( node ) > 0
                  hHash[ mxmlGetElement( node ) + "@attr"] := HB_MXMLGETATTRS( node )
               endif  
            endif
         ENDIF   

         node := mxmlGetNextSibling( node )
                    
   END WHILE
//   aadd(aHash,hHash)

return hHash

José Arias Vega

José M. C. Quintas

unread,
Jun 9, 2025, 9:19:05 PMJun 9
to oo...@googlegroups.com

sistema de faturación de Brasil.

https://github.com/JoseQuintas/sefazclass

Uso de lectura XML:

https://github.com/JoseQuintas/sefazclass/blob/master/source/ze_sefaz_xmlclass.prg

Funciones para xml

https://github.com/JoseQuintas/sefazclass/blob/master/source/ze_sefaz_xmlclass.prg

Creé las mismas funciones para MySQL y genero XML em MySQL.

Más simple que en harbour

SET cThisXml := CONCAT( cThisXml,
   '<total>',
   '<ICMSTot>',
   ze_XmlTag( 'vBC',          nIcmBas ),
   ze_XmlTag( 'vICMS',        nIcmVal ),
   ze_XmlTag( 'vICMSDeson',   '0.00' ),
   ze_XmlTag( 'vFCPUFDest',   nDifValf ),
   ze_XmlTag( 'vICMSUFDest',  nDifVali ),
   ze_XmlTag( 'vICMSUFRemet', '0.00' ),
   ze_XmlTag( 'vFCP', '0.00' ),
   ze_XmlTag( 'vBCST',        nSubBas ),
   ze_XmlTag( 'vST',          nSubVal ),
   ze_XmlTag( 'vFCPST', '0.00' ),
   ze_XmlTag( 'vFCPSTRet', '0.00' ),
   IF(  nMonoBas = 0, '',
      CONCAT( ze_XmlTag( 'qBCMonoRet', nMonoBas ),
              ze_XmlTag( 'vICMSMonoRet', ROUND( nMonoBas * nMonoAliq, 2 ) ) ) ),
   ze_XmlTag( 'vProd',        IF( nComplementar = 1, '0.00', nValPro ) ),
   ze_XmlTag( 'vFrete',       nValFre ),
   ze_XmlTag( 'vSeg',         nValSeg ),
   ze_XmlTag( 'vDesc',        nValDes ),
   ze_XmlTag( 'vII',          nIIVal ),
   ze_XmlTag( 'vIPI',         nIpiVal ),
   ze_XmlTag( 'vIPIDevol', '0.00' ),
   ze_XmlTag( 'vPIS',         nPisVal ),
   ze_XmlTag( 'vCOFINS',      nCofVal ),
   ze_XmlTag( 'vOutro',       nValOut ),
   ze_XmlTag( 'vNF',          IF( nComplementar = 1, '0.00', nValNot ) ),
   IF( nImpVal = 0, '', ze_XmlTag( 'vTotTrib',  nImpVal ) ),
   '</ICMSTot>',
   '</total>' );

José M. C. Quintas

--
Has recibido este mensaje porque estás suscrito al grupo "[oohg]" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a oohg+uns...@googlegroups.com.
Para ver este debate, visita https://groups.google.com/d/msgid/oohg/CAGuw8rU-eLPP%3Dt8iqyGZ8qT_9tRMcGyhsWyaN55J567jUXzgqA%40mail.gmail.com.
Reply all
Reply to author
Forward
0 new messages