FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin para Harbour/xHarbour Function XMLtoHash
Posts: 731
Joined: Fri Oct 07, 2005 07:42 AM
Function XMLtoHash
Posted: Tue Nov 24, 2015 01:36 PM
Buenas amigos

Como varios me han pedido alguna ayuda con esto de los XML, entiendo que esto os puede facilitar la vida,
vida durilla del programata cuando nos metemos con XML y demás :-)

Os dejo un codigo que os puede ayudar a manejar XML de SOLO ELEMENTOS, no tiene en cuenta ATRIBUTOS.
La idea es convertir XML en un Hash , en el cual podamos acceder a todos los miembros.

No encontrado o desconozco si hay algo parecido, si existe algo similar, please, decírmelo :-)

Por ejemplo este XML;
Code (fw): Select all Collapse
<?xml version="1.0" encoding="utf-8"?>
<data>
    <node1></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>


Podemos acceder de la siguiente manera;
Code (fw): Select all Collapse
  
  pRoot :=   mxmlLoadString( NIL, hb_MemoRead( file ),  @type_cb() )
  hHash := XMLtoHash( pRoot, "data" )
  
  // Podemos acceder fácilmente ;
  ??   hHash["node2"]  // Muestra val2
  ??  hHash["group"][1]["node1"] // Muestra val4
  ??  hHash["group"][2]["extras"][1]["node1"] // Muestra Extra_val24



Code (fw): Select all Collapse
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
            //OutStd( "Element[" + mxmlGetElement( node ) + "]" + " Valor[" + mxmlGetText( node,@wt ) + "]" +hb_eol() )

            if HB_HHASKEY( hHash, mxmlGetElement( node ) )
               if valtype( hHash[ mxmlGetElement( node ) ] ) <> "A"
                  hHash[ mxmlGetElement( node ) ] := mxmlGetText( node,@wt )
               else
                 // Es un array, por lo tanto, no lo tocamos
               endif   
            else                   
               hHash[ mxmlGetElement( node ) ] := mxmlGetText( node,@wt )
            endif     
            
            if empty( mxmlGetText( node,@wt ) ) // Miramos dentro
               hNext := mxmlWalkNext( node, node, MXML_DESCEND )   
               if hNext != NIL
                  if empty( hHash[ mxmlGetElement( node ) ]  )
                     // OutStd( "esta vacio----> creo array " )
                     hHash[ mxmlGetElement( node ) ] := {}
                  endif   
                   //OutStd("Recursiva")
                   hHashChild :=  NodeToHash( hNext  )
                   if hHashChild != NIL
                      AADD( hHash[ mxmlGetElement( node ) ], hHashChild )
                   endif   
               endif   
            endif
         ENDIF    

         node := mxmlGetNextSibling( node ) 
                     
   END WHILE

return hHash


También esta publicado ahora en blog: http://xthefull.blogspot.com.es/2015/11/convertir-xml-hash-en-harbour.html
Saludos

Rafa Carmona ( rafa.thefullARROBAgmail.com___quitalineas__)
Posts: 6755
Joined: Wed Feb 15, 2012 08:25 PM
Re: Function XMLtoHash
Posted: Tue Nov 24, 2015 03:16 PM

Gracias Rafa, muy útil

Cristobal Navarro

Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noción del tiempo

El secreto de la felicidad no está en hacer lo que te gusta, sino en que te guste lo que haces
Posts: 990
Joined: Wed Oct 19, 2005 02:17 PM
Re: Function XMLtoHash
Posted: Tue Nov 24, 2015 04:05 PM

Rafa,

muchas gracias.

Saludos

Posts: 8515
Joined: Tue Dec 20, 2005 07:36 PM
Re: Function XMLtoHash
Posted: Tue Nov 24, 2015 05:31 PM
Que me falta Rafa?

Code (fw): Select all Collapse
Error: Unresolved external '_HB_FUN_MXMLLOADSTRING' referenced from C:\FWH\SMPLES\XMLHASH.OBJ
Error: Unresolved external '_HB_FUN_MXMLDELETE' referenced from C:\FWH\SAMPL\XMLHASH.OBJ
Error: Unresolved external '_HB_FUN_MXMLFINDELEMENT' referenced from C:\FWH\SAMPLES\XMLHASH.OBJ
Error: Unresolved external '_HB_FUN_MXMLWALKNEXT' referenced from C:\FWH\SAMLES\XMLHASH.OBJ
Error: Unresolved external '_HB_FUN_MXMLGETTYPE' referenced from C:\FWH\SAMPES\XMLHASH.OBJ
Error: Unresolved external '_HB_FUN_MXMLGETELEMENT' referenced from C:\FWH\SMPLES\XMLHASH.OBJ
Error: Unresolved external '_HB_FUN_MXMLGETTEXT' referenced from C:\FWH\SAMPES\XMLHASH.OBJ


Gracias, saludos.

João Santos - São Paulo - Brasil - Phone: +55(11)95150-7341
Posts: 731
Joined: Fri Oct 07, 2005 07:42 AM
Re: Function XMLtoHash
Posted: Wed Nov 25, 2015 09:50 AM

Simplemente enlaza la libreria hbmxml de Harbour
Si usas hbmk2, simplemente coloca hbmxml.hbc en tu hbm

Saludos Cordiales

Saludos

Rafa Carmona ( rafa.thefullARROBAgmail.com___quitalineas__)
Posts: 8515
Joined: Tue Dec 20, 2005 07:36 PM
Re: Function XMLtoHash
Posted: Wed Nov 25, 2015 03:05 PM
Gracias Rafa, pero no funciona...

Code (fw): Select all Collapse
Application
===========
   Path and name: C:\FWH1505\samples\XMLHASH.exe (32 bits)
   Size: 3,095,552 bytes
   Compiler version: Harbour 3.2.0dev (r1501292255)
   FiveWin  Version: FWH 15.05
   Windows version: 6.1, Build 7601 Service Pack 1

   Time from start: 0 hours 0 mins 0 secs 
   Error occurred at: 11/25/15, 10:29:31
   Error description: Error BASE/3012  Argument error: MXMLFINDELEMENT
   Args:
     [   1] = U   
     [   2] = U   
     [   3] = C   data
     [   4] = U   
     [   5] = U   
     [   6] = N   1

Stack Calls
===========
   Called from:  => MXMLFINDELEMENT( 0 )
   Called from: XMLHASH.prg => XMLTOHASH( 49 )
   Called from: XMLHASH.prg => TEST( 28 )
   Called from: XMLHASH.prg => MAIN( 15 )


João Santos - São Paulo - Brasil - Phone: +55(11)95150-7341
Posts: 8515
Joined: Tue Dec 20, 2005 07:36 PM
Re: Function XMLtoHash
Posted: Wed Nov 25, 2015 03:06 PM
Code (fw): Select all Collapse
#Include "FiveWin.ch"
#Include "hbmxml.ch"
#include "common.ch"
#include "simpleio.ch"

FUNCTION Main()

   LOCAL cFile
   LOCAL File

   File := MemoRead( "TESTE.XML" )

   //? File

   cFile := TEST( File )

   // ? cFile

RETURN NIL

*PRG

FUNCTION Test( file )
 
  Local pRoot, hHash

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

  mxmlDelete( pRoot )

RETURN nil

STATIC FUNCTION type_cb( node ) ;  RETURN MXML_TEXT

// ---------------------------------------------------------------------------//
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 ) ] := mxmlGetText( node,@wt )
               else
                 // Es un array, por lo tanto, no lo tocamos
               endif   
            else                   
               hHash[ mxmlGetElement( node ) ] := mxmlGetText( node,@wt )
            endif     
            
            if empty( mxmlGetText( node,@wt ) ) // 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

/*
XML

<?xml version="1.0" encoding="utf-8"?>
<data>
    <node1></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>
*/


João Santos - São Paulo - Brasil - Phone: +55(11)95150-7341
Posts: 731
Joined: Fri Oct 07, 2005 07:42 AM
Re: Function XMLtoHash
Posted: Thu Nov 26, 2015 08:56 AM
Querido Amigo,

Estas cargando 2 veces el fichero. ¿ Porque ? Solo tú lo sabes :-)

Code (fw): Select all Collapse
FUNCTION Main()

 TEST( "TESTE.XML" )

RETURN NIL
Saludos

Rafa Carmona ( rafa.thefullARROBAgmail.com___quitalineas__)
Posts: 8515
Joined: Tue Dec 20, 2005 07:36 PM
Re: Function XMLtoHash
Posted: Thu Nov 26, 2015 12:01 PM
Resuelto,

gracias, Rafa Carmona.

Code (fw): Select all Collapse
#Include "FiveWin.ch"
#Include "hbmxml.ch"

FUNCTION Main()

   LOCAL cFile := "TESTE.XML"

   TEST( cFile )

RETURN NIL

*PRG

FUNCTION Test( file )
 
  Local pRoot, hHash

  pRoot := mxmlLoadString( NIL, hb_MemoRead( file ),  @type_cb() )
  hHash := XMLtoHash( pRoot, "data" )

  // Podemos acceder fácilmente ;
  ?  hHash["node2"]  // Muestra val2

  ?  hHash["group"][1]["node1"] // Muestra val4

  ?  hHash["group"][2]["extras"][1]["node1"] // Muestra Extra_val24

  mxmlDelete( pRoot )

RETURN nil

STATIC FUNCTION type_cb( node ) ;  RETURN MXML_TEXT

// ---------------------------------------------------------------------------//
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 ) ] := mxmlGetText( node,@wt )
               else
                 // Es un array, por lo tanto, no lo tocamos
               endif   
            else                   
               hHash[ mxmlGetElement( node ) ] := mxmlGetText( node,@wt )
            endif     
            
            if empty( mxmlGetText( node,@wt ) ) // 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

/*
XML

<?xml version="1.0" encoding="utf-8"?>
<data>
    <node1></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>
*/


João Santos - São Paulo - Brasil - Phone: +55(11)95150-7341
Posts: 1710
Joined: Tue Oct 28, 2008 06:26 PM
Re: Function XMLtoHash
Posted: Thu Nov 26, 2015 02:58 PM

Rafa

La cabecera hbmxml.ch me la podes pasar.

Gracias.

Saludos,

Adhemar

Saludos,



Adhemar C.
Posts: 8515
Joined: Tue Dec 20, 2005 07:36 PM
Re: Function XMLtoHash
Posted: Thu Nov 26, 2015 03:13 PM
Code (fw): Select all Collapse
/*
 * Harbour Project source code:
 *    MINIXML functions wrapper
 *
 * Copyright 2010-2011 Petr Chornyj <myorg63@mail.ru>
 * www - <!-- m --><a class="postlink" href="http://harbour-project.org">http://harbour-project.org</a><!-- m -->
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this software; see the file COPYING.txt.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307 USA (or visit the web site <!-- m --><a class="postlink" href="http://www.gnu.org/">http://www.gnu.org/</a><!-- m -->).
 *
 * As a special exception, the Harbour Project gives permission for
 * additional uses of the text contained in its release of Harbour.
 *
 * The exception is that, if you link the Harbour libraries with other
 * files to produce an executable, this does not by itself cause the
 * resulting executable to be covered by the GNU General Public License.
 * Your use of that executable is in no way restricted on account of
 * linking the Harbour library code into it.
 *
 * This exception does not however invalidate any other reasons why
 * the executable file might be covered by the GNU General Public License.
 *
 * This exception applies only to the code released by the Harbour
 * Project under the name Harbour.  If you copy code from other
 * Harbour Project or Free Software Foundation releases into a copy of
 * Harbour, as the General Public License permits, the exception does
 * not apply to the code that you add in this way.  To avoid misleading
 * anyone as to the status of such modified files, you must delete
 * this exception notice from them.
 *
 * If you write modifications of your own for Harbour, it is your choice
 * whether to permit this exception to apply to your modifications.
 * If you do not wish that, delete this exception notice.
 *
 */

#ifndef HBMXML_CH_
#define HBMXML_CH_

#define MXML_TAB                8   /* Tabs every N columns */

#define MXML_NO_CALLBACK        0   /* Don't use a type callback */
#define MXML_INTEGER_CALLBACK   1   /* Treat all data as integers */
#define MXML_OPAQUE_CALLBACK    2   /* Treat all data as opaque */
#define MXML_REAL_CALLBACK      3   /* Treat all data as real numbers */
#define MXML_TEXT_CALLBACK      4   /* Treat all data as text */
#define MXML_IGNORE_CALLBACK    5   /* Ignore all non-element content */

#define MXML_NO_PARENT          0

#define MXML_IGNORE             -1

#define MXML_ELEMENT            0
#define MXML_INTEGER            1
#define MXML_OPAQUE             2
#define MXML_REAL               3
#define MXML_TEXT               4
#define MXML_CUSTOM             5

#define MXML_DESCEND            1   /* Descend when finding/walking */
#define MXML_NO_DESCEND         0   /* Don't descend when finding/walking */
#define MXML_DESCEND_FIRST      -1  /* Descend for first find */

#define MXML_WS_BEFORE_OPEN     0   /* Callback for before open tag */
#define MXML_WS_AFTER_OPEN      1   /* Callback for after open tag */
#define MXML_WS_BEFORE_CLOSE    2   /* Callback for before close tag */
#define MXML_WS_AFTER_CLOSE     3   /* Callback for after close tag */

#define MXML_ADD_BEFORE         0   /* Add node before specified node */
#define MXML_ADD_AFTER          1   /* Add node after specified node */
#define MXML_ADD_TO_PARENT      NIL /* Add node relative to parent */

#define MXML_SAX_CDATA          1
#define MXML_SAX_COMMENT        2
#define MXML_SAX_DATA           3
#define MXML_SAX_DIRECTIVE      4
#define MXML_SAX_ELEMENT_CLOSE  5
#define MXML_SAX_ELEMENT_OPEN   6

#endif /* HBMXML_CH_ */


João Santos - São Paulo - Brasil - Phone: +55(11)95150-7341
Posts: 1710
Joined: Tue Oct 28, 2008 06:26 PM
Re: Function XMLtoHash
Posted: Thu Nov 26, 2015 03:30 PM

Gracias Joao

Saludos,

Adhemar

Saludos,



Adhemar C.
Posts: 8515
Joined: Tue Dec 20, 2005 07:36 PM
Re: Function XMLtoHash
Posted: Wed Jan 05, 2022 09:49 AM

Buen día. ¿Alguien tiene el hbmk.hbm para publicar para que pueda ver cómo es internamente, por favor?

Regards, saludos.

João Santos - São Paulo - Brasil - Phone: +55(11)95150-7341

Continue the discussion