martes, 25 de abril de 2017

Convertir XML a Hash en Harbour ( Update V )


Bueno, pues de probar con un montón de XML diferentes , me encuentro que uno de tantos cientos probamos, no lo hace como se esperaba.

Simplificando y reduciendo el XML para ver donde está el problema;


<?xml version="1.0" encoding="utf-8"?>
 <UpdateCustomerProfile> 
     <request> 
          <Id>001</Id> 
          <ReservationNumber>123456</ReservationNumber>
          <Email> 
                 <string>uno@moo.com</string>
                 <string>dos@moo.com</string>
          </Email>
     </request>
</UpdateCustomerProfile>

Al pasar por la función XMTOHASH( ), el efecto que ocurre es que solo tendremos el valor
de string, con el ultimo valor, dos@moo.com

¿ Y porque ocurre esto ? 

Ocurre simplemente, porque se ha llegado al final , y no tiene hijos,  y como el node se llama igual, lo que hace la función es volver asignarle a hash con la clave string ,que si tenemos, con el nuevo valor.
La consecuencia es que no podemos tener los valores de ninguna de las maneras.


Como podéis observa en la imagen, el hash solo podemos tener el último valor del string.

Bien, ¿ como solucionarlo  ? 

Sencillamente, vamos a crear un array de childs, que en caso que  la clave sea igual a lo que tengo, se guardará posteriormente para remplazar el valor que hay por este array child.
En casos como este, tendremos que preguntar si el valor del hash["string"] de que tipo es,
CARACTER o ARRAY, para procesar posteriormente el hash.

Aquí el código final, en color azul, el parche aplicar a la funcion recursiva NodeToHash();


STATIC FUNCTION NodeToHash( node ) Local hNext Local hHashChild := {=>} Local hHash := {=>} Local node2 Local hChild := {=>}, cKey /* hChild es un hash, que tiene la key en el cual vamos añadiendo
en el array los elementos iguales. */ WHILE node != NIL IF mxmlGetType( node ) == MXML_ELEMENT if HB_HHASKEY( hHash, mxmlGetElement( node ) ) if valtype( hHash[ mxmlGetElement( node ) ] ) <> "A" if empty( hChild ) hChild[ mxmlGetElement( node ) ] := {} aadd( hChild[ mxmlGetElement( node ) ] , hHash[ mxmlGetElement( node ) ] ) aadd( hChild[ mxmlGetElement( node ) ] , mxmlGetOpaque( node ) ) // Mas el valor del nuevo nodo else aadd( hChild[ mxmlGetElement( node ) ], mxmlGetOpaque( node ) ) // Mas el valor del nuevo nodo endif 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
 // En caso que el array tenga mas de un elemento, tenemos que alimentarlo
// con el array de su clave.
   if !empty( hChild )
      cKey := hb_HKeyAt( hChild, 1) 
      hHash[ cKey ] := hChild[ cKey ]
   endif   
return hHash

Como consecuencia de este trozo de código ,  ahora tenemos en un array los elementos disponibles;

Si si, eso esta muy bien, pero algo como esto; ( Incrédulos ;-)  )


<?xml version="1.0" encoding="utf-8"?>
 <UpdateCustomerProfile> 
     <request> 
          <Id>001</Id> 
          <ReservationNumber>123456</ReservationNumber>
          <Email> 
                 <string>uno@moo.com</string>
                 <string>dos@moo.com</string>
                 <string>
                      <string>compicado@es.es</string>
                 </string>
          </Email>
     </request>
</UpdateCustomerProfile>




Disfruten del parche! 

Android y Git. Disponer del hash automáticamente.

Una de las cosas a las que estoy acostumbrado, es tener siempre en mi código, el hash/tag/versión del control de versiones que estoy usan...