martes, 24 de noviembre de 2015

Convertir XML a Hash en Harbour ( update II )



En eso que estaba yo pensando en como acceder a un XML que contiene solo nodos de elementos,
sin atributos, sin tener que estar continuamente haciendo búsquedas.

Pues vamos a dotarle a Harbour la manera de recorrer cualquier nodo, y devolver un Hash con
el contenido.

Los subnodos, simplemente serán arrrays con Hash.
He aquí el codigo de ejemplo;

UDPATE. Soporte para atributos.
Ahora, se crea un hash con el  nombre del elemento, mas @attribute  que va a contener un hash con los atributos del nodo, de esta manera para obtener el nombre del nodo, node1;
hHash["node1@attribute"]["nombre"] mostrará pepe

UPDATE II. Fix espacios en blanco
Se detecta que un nodo, <nodo>Ejemplo XML</nodo>
El valor del Hash["nodo"] será igual a Ejemplo, y debería ser Ejemplo XML
Viktor me ha iluminado, comentando que hay que usar OPAQUE

XML

<?xml version="1.0" encoding="utf-8"?>
<data>
    <node1 nombre="pepe">Ejemplo XML</node1>
    <node2>val2</node2>
    <node3>val3</node3>
    <group>
        <node1>val4</node1>
        <node2>val5</node2>
        <node3>val6</node3>
    </group>
    <group>
        <node1>val24</node1>
        <node2>val25</node2>
        <node3>val26</node3>
      <extras>
            <node1>Extra_val24</node1>
            <node2>Extra_val25</node2>
            <node3>Extra_val26</node3>
        </extras>
    </group>
    <node7>val7</node7>
    <node8>val8</node8>
</data>

PRG

FUNCTION Test( file )
  Local pRoot, hHash

  pRoot :=   mxmlLoadString( NIL, hb_MemoRead( file ),  @type_cb() )
  hHash := XMLtoHash( pRoot, "data" )
 
  // Podemos acceder fácilmente ;
  ??  hHash["node1"]  // Muestra Ejemplo XML
  ??  hHash["node2"]  // Muestra val2  ??  hHash["group"][1]["node1"] // Muestra val4
  ??  hHash["group"][2]["extras"][1]["node1"] // Muestra Extra_val24

    ??  hHash["node1@attribute"]["nombre]  // Muestra pepe

     mxmlDelete( pRoot )

 RETURN nil

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 wt := 0
   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 HB_MXMLGETATTRSCOUNT( node ) > 0
               hHash[ mxmlGetElement( node ) + "@attribute"] := HB_MXMLGETATTRS( node )
            endif  
 

              if empty( mxmlGetOpaque( node ) ) // Miramos dentro
               hNext := mxmlWalkNext( node, node, MXML_DESCEND )  
               if hNext != NIL
                  if empty( hHash[ mxmlGetElement( node ) ]  )
                     hHash[ mxmlGetElement( node ) ] := {}
                  endif  
                   hHashChild :=  NodeToHash( hNext  )
                   if hHashChild != NIL
                      AADD( hHash[ mxmlGetElement( node ) ], hHashChild )
                   endif  
               endif  
            endif
         ENDIF   

         node := mxmlGetNextSibling( node )
                    
   END WHILE

RETURN hHash
 

Aqui muestra pantallazo de obtener de un XML de SEPA de prueba;
 
 

miércoles, 4 de noviembre de 2015

Ignorar fichero del repositorio en Git


Cuando queremos ignorar un fichero o directorio en concreto, y este fichero no forma parte del repositorio, pero si en la carpeta de trabajo, por ejemplo, los ficheros *.obj , *.log o similar, que no queremos que formen parte, pero que son necesarios en el proyecto.

Pues tan simple como crear un fichero .gitignore, y añadirlos;
/obj/
*.log

Bien, pero , ¿ Y si el fichero en cuestión SI quiero que este en el repositorio ?  por ejemplo, un fichero inicial de configuración, pero NO quiero que se haga un seguimiento, por la sencilla razón,
que contiene los passwords o otros parámetros que no queremos que se actualice.

Pues para eso existe un comando;
git update-index 

Como la finalidad no es explicar TODO lo que hace el comando, vamos directamente a lo que nos interesa, aqui el enlace al comando, https://www.kernel.org/pub/software/scm/git/docs/git-update-index.html

Imaginemos que tenemos un fichero, config.ini, que contiene las diversas opciones.
git update-index --asume-unchanged config.ini

Atentos, git update-index solo maneja ficheros, no directorios.

Ahora, si modificas el fichero config.ini, verás que para Git, no lo has tocado, evitando así tener
que subirlo al repositorio. 

Ah, pero si ahora quiero que Git vuelva a tener encuenta a nuestro fichero, config.ini, pues 
tenemos el comando;
git update-index --no--asume-unchanged config.ini

Para saber que ficheros están como 'ocultos' , usamos el comando, la h en minúscula nos lo indica;
git ls-files -v  

H file.txt
h config.ini

Así, podemos crearnos unos alias, creando-comandos-en-git, para manejar más fácil

[alias]
hide = update-index --assume-unchanged
unhide = update-index --no--assume-unchanged

Aplicando el alias;
git hide config.ini



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