jueves, 28 de abril de 2016

Convertir XML a Hash en Harbour ( Update IV )



Bueno, esto ya tiene más partes que el padrino. ;-)

Resulta que un amigo mío, me envia un XML de como leer unos atributos, que no encuentra la forma.

El XML de ejemplo, ver más abajo ,,  que no es capaz de montar en cuestión;

<cfdi:Conceptos>
  <cfdi:Concepto noIdentificacion="a" importe="1.123456" valorUnitario="1.123456" cantidad="0.0" descripcion="a" unidad="a">
      <cfdi:InformacionAduanera aduana="3" numero="a" fecha="1967-08-13"/>
      <cfdi:InformacionAduanera aduana="4" numero="a" fecha="1967-08-13"/>
  </cfdi:Concepto>


Pues resulta, que <cfdi:InformacionAduanera/> nos muestra un bonito valor vacio.
Este parche , en la funcion  NodeToHash( node  ) ,soluciona el problema;

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

   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
                else
                   if HB_MXMLGETATTRSCOUNT( node ) > 0
                     if empty( hHash[ mxmlGetElement( node ) ] )
                        hHash[ mxmlGetElement( node ) ] := {}
                     endif  
                 AADD( hHash[ mxmlGetElement( node ) ], HB_MXMLGETATTRS( node ) )
                   endif  
               endif
            else  
               if HB_MXMLGETATTRSCOUNT( node ) > 0
                  hHash[ mxmlGetElement( node ) + "@attr"] := HB_MXMLGETATTRS( node )
               endif  
            endif
         ENDIF   

         node := mxmlGetNextSibling( node )
                    
   END WHILE

return hHash



De paso, pongo aqui el ejemplo de como leer el nodo de los impuestos, 

FUNCTION Test_xml( )
  Local pRoot, hHash, hImpuestos, hPrecios, hVarios
  
  pRoot :=   mxmlLoadString( NIL, hb_MemoRead( hb_dirBase() +"xml.xml" ),  @type_cb() )
  hHash := XMLtoHash( pRoot ) 


  for each hImpuestos in  hHash["cfdi:Comprobante"][1]["cfdi:Impuestos"][1]
 
      do case
          case hImpuestos:__enumKey == "cfdi:Retenciones"
              hVarios := hImpuestos[1]["cfdi:Retencion"]
              for each hPrecios in hVarios
                  Alert( "Importe Retencion:" + hPrecios["importe"] )
              next

         case hImpuestos:__enumKey == "cfdi:Traslados"
              hVarios := hImpuestos[1]["cfdi:Traslado"]
              for each hPrecios in hVarios
                  Alert( "Importe Traslados:" + hPrecios["importe"] )
              next

      end case
  next
 

  mxmlDelete( pRoot )

 RETURN nil  

 


Podemos ver los 2 elementos 
 
Y el valor de uno de ellos 


XML de ejemplo;
<?xml version="1.0" encoding="UTF-8"?>
<cfdi:Comprobante MontoFolioFiscalOrig="1.123456" noCertificado="aaaaaaaaaaaaaaaaaaaa" formaDePago="String" motivoDescuento="a" metodoDePago="a" NumCtaPago="aaaa" certificado="String" sello="String" condicionesDePago="a" FolioFiscalOrig="String" descuento="1.123456" fecha="2001-12-17T09:30:47.0Z" subTotal="1.123456" SerieFolioFiscalOrig="String" LugarExpedicion="a" total="1.123456" Moneda="String" folio="a" serie="a" TipoCambio="String" tipoDeComprobante="ingreso" version="3.2" FechaFolioFiscalOrig="2001-12-17T09:30:47.0Z" xsi:schemaLocation="http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv32.xsd" xmlns:cfdi="http://www.sat.gob.mx/cfd/3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <cfdi:Emisor rfc="&amp;&amp;&amp;&amp;000000,," nombre="a">
        <cfdi:DomicilioFiscal municipio="a" colonia="a" referencia="a" calle="a" noExterior="a" localidad="a" codigoPostal="aaaaa" noInterior="a" pais="a" estado="a"/>
        <cfdi:ExpedidoEn municipio="a" colonia="a" referencia="a" calle="a" noExterior="a" localidad="a" codigoPostal="String" noInterior="a" pais="a" estado="a"/>
        <cfdi:RegimenFiscal Regimen="a"/>
        <cfdi:RegimenFiscal Regimen="a"/>
    </cfdi:Emisor>
    <cfdi:Receptor rfc="&amp;&amp;&amp;&amp;000000,," nombre="a">
        <cfdi:Domicilio municipio="a" colonia="a" referencia="a" calle="a" noExterior="a" localidad="a" codigoPostal="String" noInterior="a" pais="a" estado="a"/>
    </cfdi:Receptor>
    <cfdi:Conceptos>
        <cfdi:Concepto noIdentificacion="a" importe="1.123456" valorUnitario="1.123456" cantidad="0.0" descripcion="a" unidad="a">
            <cfdi:InformacionAduanera aduana="3" numero="a" fecha="1967-08-13"/>
            <cfdi:InformacionAduanera aduana="4" numero="a" fecha="1967-08-13"/>
        </cfdi:Concepto>
    </cfdi:Conceptos>
    <cfdi:Impuestos totalImpuestosRetenidos="1.123456" totalImpuestosTrasladados="1.123456">
        <cfdi:Retenciones>
            <cfdi:Retencion importe="2.123456" impuesto="ISR"/>
            <cfdi:Retencion importe="3.123456" impuesto="ISR"/>
        </cfdi:Retenciones>
        <cfdi:Traslados>
            <cfdi:Traslado importe="4.123456" tasa="1.123456" impuesto="IVA"/>
            <cfdi:Traslado importe="5.123456" tasa="1.123456" impuesto="IVA"/>
        </cfdi:Traslados>
    </cfdi:Impuestos>
    <cfdi:Complemento/>
    <cfdi:Addenda/>
</cfdi:Comprobante>