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.
******************************************************************************************
* 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