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;
No hay comentarios:
Publicar un comentario