de XML a Hash

25 views
Skip to first unread message

José Santos Arias Vega

unread,
Jun 9, 2025, 5:48:56 PM6/9/25
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
Reply all
Reply to author
Forward
0 new messages