MXML Help

General Help regarding HMG, Compilation, Linking, Samples

Moderator: Rathinagiri

User avatar
Rathinagiri
Posts: 5471
Joined: Tue Jul 29, 2008 6:30 pm
DBs Used: MariaDB, SQLite, SQLCipher and MySQL
Location: Sivakasi, India
Contact:

MXML Help

Post by Rathinagiri »

Hi,

Does anybody use hbmxml library?

I want to clarify a doubt.

I have an element like the below: (taken from Harbour-hbmxml test file:test.xml

Code: Select all

<text>Media Source</text>
Now, if I want to get the string and give the following statement

Code: Select all

nNum := MXML_TEXT
? mxmlGetText( hNode, @nNum )
It gives only 'Media' as the result. and not the 'Media Source' (ie., only the first word is retrieved.)

Can you help me out?
East or West HMG is the Best.
South or North HMG is worth.
...the possibilities are endless.
User avatar
Rathinagiri
Posts: 5471
Joined: Tue Jul 29, 2008 6:30 pm
DBs Used: MariaDB, SQLite, SQLCipher and MySQL
Location: Sivakasi, India
Contact:

Re: MXML Help

Post by Rathinagiri »

Hi,

As of now, I have a work around.

I am using another function to get the whole node string and strip the tag. I know it may not give the accurate result always. However, now it is working for most of the cases.

Code: Select all

? striptag( mxmlSaveAllocString( hElement, MXML_NO_CALLBACK ), 'link:label' )

function striptag( cStr, cTag )
   local nEnd := rat( '</' + cTag + '>', cStr )
   local nStart := rat( '">', cStr )
   if nStart > 0 .and. nEnd > 0
      return s_ubstr ( cStr, nStart + 2, nEnd - ( nStart + 2 ) )
   else
      return cStr
   endif
   return nil   

East or West HMG is the Best.
South or North HMG is worth.
...the possibilities are endless.
User avatar
mol
Posts: 3720
Joined: Thu Sep 11, 2008 5:31 am
Location: Myszków, Poland
Contact:

Re: MXML Help

Post by mol »

Hi!
I want to read xml file, but, I can't get subnode value.
Here is sample of XML:

Code: Select all

<?xml version="1.0" encoding="ISO-8859-2"?>
<tabela_kursow typ="A" uid="14a165">
   <numer_tabeli>165/A/NBP/2014</numer_tabeli>
   <data_publikacji>2014-08-27</data_publikacji>
   <pozycja>
      <nazwa_waluty>bat (Tajlandia)</nazwa_waluty>
      <przelicznik>1</przelicznik>
      <kod_waluty>THB</kod_waluty>
      <kurs_sredni>0,0995</kurs_sredni>
   </pozycja>
   <pozycja>
      <nazwa_waluty>dolar amerykański</nazwa_waluty>
      <przelicznik>1</przelicznik>
      <kod_waluty>USD</kod_waluty>
      <kurs_sredni>3,1764</kurs_sredni>
   </pozycja>
</tabela_kursow>
and some piece of code

Code: Select all

FUNCTION asXML( xml )

   LOCAL cText := "", c
   LOCAL wt := 1
   LOCAL node, subnode
altd()

   node := mxmlFindElement( xml, xml, "tabela_kursow", NIL, NIL, MXML_DESCEND )
   
   IF Empty( node )
      RETURN "<---brak--->"
   ENDIF
	debugmsg("typ", mxmlElementGetAttr( node, "typ" ), "UID",mxmlElementGetAttr( node, "uid" ), "Custom", mxmlGetCustom(node))
   subnode := mxmlGetFirstChild( node )
   DO WHILE .t.
      IF mxmlGetType( subnode ) == MXML_ELEMENT
        c := mxmlGetElement( subnode )
		if c == "numer_tabeli"
			wt := MXML_TEXT
			c += ">>>" +mxmlGetText(subnode, @wt) + "<<<" 
		endif
        cText += ( c + " " )
      ENDIF
	if Empty( subnode := mxmlGetNextSibling( subnode ) )
		exit
	endif
   ENDDO

   RETURN cText

Have sb. knowledge about XML handling?
User avatar
Rathinagiri
Posts: 5471
Joined: Tue Jul 29, 2008 6:30 pm
DBs Used: MariaDB, SQLite, SQLCipher and MySQL
Location: Sivakasi, India
Contact:

Re: MXML Help

Post by Rathinagiri »

Hi Marek,

It is easy to go to any level of sub nodes..
Please see this code

Code: Select all

         hSchema := mxmlFindElement( hTree, hTree, "schema",,, MXML_DESCEND )
         hAnnotation := mxmlFindElement( hSchema, hTree, "annotation",,, MXML_DESCEND )
         hAppInfo := mxmlFindElement( hAnnotation, hTree, "appinfo",,, MXML_DESCEND )
Here, the schema is schema->annotation->appinfo.

The first parameter to mxmlFindElement would be the immediate parent handle.
East or West HMG is the Best.
South or North HMG is worth.
...the possibilities are endless.
User avatar
andyglezl
Posts: 1461
Joined: Fri Oct 26, 2012 7:58 pm
Location: Guadalajara Jalisco, MX
Contact:

Re: MXML Help

Post by andyglezl »

Hola

En algún momento baje este ejemplo, pero no he tiempo de probarlo.
Por lo que entendí, baja un archivo desde el "Link" que se le da como parametro
y se obtiene información en base a preguntar por algunos "tags" en especial.
Espero que les de una idea...
-----------------------------------------------------------------------------
Hi there

Somewhere down this example, but I have no time to try it.
From what I understand, downloads a file from the "Link" that is given as parameter
and information is obtained on the basis of asking for some "tags" in particular.
Hope you an idea ...

Code: Select all

//------------------------------------------------------------------------------
/********* * * * * *
* PrevisaoDoTempo
* Stanis - stanis.luksys@gmail.com
* Parametro: string com o 'nome da cidade, estado'
* Retorno: hash com dados sobre o clima
* hash["CidadeBase"]       => Cidade localizada com este nome
* hash["CondicaoAtual"]    => Condição climatica atual na cidade
* hash["TemperaturaAtual"] => Temperatura atual na cidade
* hash["UmidadeAtual"]     => Umidade atual na cidade
* hash["VentoAtual"]       => Vento atual na cidade (direcao e velocidade)
* hash["aProximosDias"]    => Array com a previsao para os proximos dias
*       aProximosDias = { cDiaDaSemana, cTempMax, cTempMin, cCondicao }
*/
FUNCTION EdoTiempo( cCidade )

    LOCAL oHttp, cXML, oXML, cLink
    LOCAL oCidade,    oTemperatura, oUmidade, oVento, oCondicao
    LOCAL oPrevisao, oTagAtual, oIterator

    LOCAL cDia, cMax, cMin, cCond, i
    LOCAL    aDias := {}

    LOCAL hPrevisaoDoTempo    := HB_Hash()
    LOCAL hDiasSemana         := HB_Hash()

    hDiasSemana["dom"] := "Domingo"
    hDiasSemana["seg"] := "Segunda-feira"
    hDiasSemana["ter"] := "Terçaa-feira"
    hDiasSemana["qua"] := "Quarta-feira"
    hDiasSemana["qui"] := "Quinta-feira"
    hDiasSemana["sex"] := "Sexta-feira"
    hDiasSemana["sáb"] := "Sábado"

    cCidade := StrTran( AllTrim( cCidade ), " ", "%20" )

    oHttp:= TIpClientHttp():new( "http://www.google.com/ig/api?weather="+cCidade+"&hl=pt-br" )
    IF ! oHttp:open()
        MsgInfo( "No se pudo abrir el Sitio...", "AVISO" )
        RETURN Nil
    ENDIF
    cXML := oHttp:readAll() // ;  MsgInfo( cXML, "AVISO" )
    oHttp:close()

    oXML := TXmlDocument():New( cXML )
    IF oXML:nError != HBXML_ERROR_NONE
        MsgInfo( "Hubo un error en la página, verifique", "AVISO" )
        RETURN Nil
    ENDIF

     oCidade       := oXML:findfirst( "city" )
     oCondicao     := oXML:findfirst( "condition" )
     oTemperatura  := oXML:findfirst( "temp_c" )
     oUmidade      := oXML:findfirst( "humidity" )
     oVento        := oXML:findfirst( "wind_condition" )

    oPrevisao := oXML:findfirst( "forecast_conditions" )
    IF oPrevisao == NIL
         RETURN hPrevisaoDoTempo
    ENDIF

    DO WHILE .T.
        oIterator := TXmlIterator():New( oPrevisao )
        DO WHILE .T.
           oTagAtual := oIterator:Next()
           IF oTagAtual == NIL
              aAdd( aDias, { cDia, cMin, cMax, cCond } )
              EXIT
           ELSE
              IF oTagAtual:cName == "day_of_week"
                  cDia    := oTagAtual:aAttributes[ "data" ]
              ELSEIF oTagAtual:cName == "low"
                  cMin    := StrZero( val( oTagAtual:aAttributes[ "data" ] ), 2 )
              ELSEIF oTagAtual:cName == "high"
                  cMax    := StrZero( val( oTagAtual:aAttributes[ "data" ] ), 2 )
              ELSEIF oTagAtual:cName == "condition"
                  cCond    := oTagAtual:aAttributes[ "data" ]
              ENDIF
           ENDIF
        ENDDO
        oPrevisao := oXML:findnext()
        IF oPrevisao == NIL
           EXIT
        ENDIF
    ENDDO

    hPrevisaoDoTempo["CidadeBase"]       = oCidade:aAttributes[ "data" ]
    hPrevisaoDoTempo["CondicaoAtual"]    = oCondicao:aAttributes[ "data" ]
    hPrevisaoDoTempo["TemperaturaAtual"] = oTemperatura:aAttributes[ "data" ]
    hPrevisaoDoTempo["UmidadeAtual"]     = oUmidade:aAttributes[ "data" ]
    hPrevisaoDoTempo["VentoAtual"]       = oVento:aAttributes[ "data" ]
    hPrevisaoDoTempo["aProximosDias"]    = {}
    FOR i:=1 to LEN( aDias )
        AAdd( hPrevisaoDoTempo["aProximosDias"], { hDiasSemana[aDias[i][1]], aDias[i][3], aDias[i][2], aDias[i][4] } )
    NEXT

    //------------------------------------------------------------------------------
    MSGINFO( hPrevisaoDoTempo )
    //------------------------------------------------------------------------------

RETURN hPrevisaoDoTempo
Andrés González López
Desde Guadalajara, Jalisco. México.
User avatar
Clip2Mania
Posts: 99
Joined: Fri Jun 13, 2014 7:16 am
Location: Belgium

Re: MXML Help

Post by Clip2Mania »

For that matter, can somebody explain how I can compile this (and other) harbour examples in HMG?
(after replacing the character-oriented code with HMG controls, of course :) )
I.e., which paths to put, in which case do I have to include the .ch, and in which case not, where to put them?
I'm very interested in the above xml case, but I cannot compile the example [drive]:\hmg.3.3.1\HARBOUR\contrib\hbmxml\tests\testxml.prg :(
User avatar
mol
Posts: 3720
Joined: Thu Sep 11, 2008 5:31 am
Location: Myszków, Poland
Contact:

Re: MXML Help

Post by mol »

Hi guys!
I want to post all functions working with posted XML sample.

Maybe it will be useful for someone.

A bug in mxmlGetText function still exists, this function does not return whole element text value, only first word, but, I've replaced it with StripTag function defined below.

Code: Select all

*------------------------
function ImportujKursyWalut
	param cPlikTabela

	LOCAL xml

	if hb_FileExists( cPlikTabela)
		xml := simplexml_load_file(cPlikTabela )
	else
		return .f.
	endif
    if s_mxml_error
         MsgStop("Błąd w xml", "hbmxml:", s_mxml_error_msg, hb_eol() )
    else

		msgdebug(cPlikTabela,asXML(xml))
	endif
	
	
return .t.
*----------------------
STATIC PROCEDURE my_mxmlError( cErrorMsg )

   s_mxml_error_msg := cErrorMsg
   s_mxml_error := .T.

   RETURN

*----------------------
function simplexml_load_file
	param cFileName

   return mxmlLoadString( NIL, hb_MemoRead( cFileName ), @type_callback() )
	// I don't know why below line does not work fine, returning all elements empty
	//RETURN mxmlLoadString( NIL, hb_MemoRead( cFileName ), MXML_TEXT_CALLBACK )

*----------------------
function asXML( xml )

	local cText := "", c
	local nElementType := 0
	local xTabela, xmlElement, xmlPozycja, xmlElementPozycji
	local aWaluty := {}
	local aPozycja := {}
	
			// z dokumentacji - wyszukiwanie jesli podamy attr lub value to ograniczamy szukanie
			//node = mxmlFindElement(tree, tree, "name","attr", "value",MXML_DESCEND);
			
	xTabela := mxmlFindElement( xml, xml, "tabela_kursow", NIL, NIL, MXML_DESCEND )

	if empty( xTabela )
		return nil
	endif

	c_Tabela_Kursow_typ := mxmlElementGetAttr( xTabela, "typ" )
	c_Tabela_Kursow_uid := mxmlElementGetAttr( xTabela, "uid" )
	
	xmlElement := mxmlGetFirstChild( xTabela )
   
	do while .t.
		if mxmlGetType( xmlElement ) == MXML_ELEMENT
			cElementName := lower(mxmlGetElement( xmlElement ))
			do case
				case cElementName == "numer_tabeli"
					nElementType := MXML_TEXT
					c_numer_tabeli := mxmlGetText(xmlElement, @nElementType)
				case cElementName == "data_publikacji"
					nElementType := MXML_TEXT
					c_data_publikacji := mxmlGetText(xmlElement, @nElementType)
					d_data_publikacji := stod(strtran(c_data_publikacji, "-",""))

				case cElementName == "pozycja"
					aPozycja := { }
					
					//xmlPozycja := mxmlFindElement( xmlElement, xml, "pozycja", NIL, NIL, MXML_DESCEND )
					
					//if !empty(xmlPozycja)
						xmlElementPozycji := mxmlGetFirstChild( xmlElement )
						
						do while .t.
							cElementName := lower(mxmlGetElement( xmlElementPozycji ))
							do case
							case cElementName == "nazwa_waluty"
								nElementType	:= MXML_TEXT
								// it can't be used to string fields because of bug in mxml library, I think
								//c_nazwa_waluty	:= mxmlGetText(xmlElementPozycji, @nElementType)		
								// but solution posted by Rathinagiri' solution works almost perfect
								c_nazwa_waluty	:= striptag(mxmlSaveAllocString( xmlElementPozycji, MXML_NO_CALLBACK ), 'nazwa_waluty')
								
							case cElementName == "przelicznik"
								nElementType	:= MXML_TEXT
								n_przelicznik	:= val( mxmlGetText(xmlElementPozycji, @nElementType) )
								
							case cElementName == "kod_waluty"
								nElementType	:= MXML_TEXT
								c_kod_waluty	:= mxmlGetText(xmlElementPozycji, @nElementType)
								
							case cElementName == "kurs_sredni"
								nElementType	:= MXML_TEXT
										//conversion to real type of value
								n_kurs_sredni	:= val( strtran( mxmlGetText(xmlElementPozycji, @nElementType), "," , "."))
							
							endcase
							if Empty( xmlElementPozycji := mxmlGetNextSibling( xmlElementPozycji ) )
								exit
							endif
							
						enddo
						
						aAdd(aWaluty, { c_kod_waluty, c_nazwa_waluty, n_przelicznik, n_kurs_sredni } )
					//endif
			endcase
		endif
		
		if Empty( xmlElement := mxmlGetNextSibling( xmlElement ) )
			exit
		endif
		
	enddo

	msgdebug(c_Tabela_Kursow_typ, c_Tabela_Kursow_uid, c_numer_tabeli, c_data_publikacji, d_data_publikacji, len(aWaluty), aWaluty)
	
   RETURN {c_Tabela_Kursow_typ, c_Tabela_Kursow_uid, c_numer_tabeli, c_data_publikacji, d_data_publikacji, len(aWaluty), aWaluty}
/*
 * 'type_callback()' - XML data type callback for mxmlLoadFile()...
 */

/* O - Data type */
/* I - Element node */


FUNCTION type_callback( hNode )

   LOCAL cType                            /* Type string */

   /*
    * You can lookup attributes and/or use the element name, hierarchy, etc...
    */

   IF Empty( cType := mxmlElementGetAttr( hNode, "type" ) )
      cType := mxmlGetElement( hNode )
	  if ctype = "nazwa_waluty"
		altd()
	  endif
   ENDIF

   SWITCH Lower( cType )
	   CASE "integer" ;  RETURN MXML_INTEGER
	   CASE "opaque"  ;  RETURN MXML_OPAQUE
	   CASE "real"    ;  RETURN MXML_REAL
   ENDSWITCH

   RETURN MXML_TEXT
*-------------------
function striptag( cStr, cTag )
   local nEnd 
   local nStart
   
   nStart := at('>', cStr )+1
   nEnd := rat( '<', cStr )
   nCount := nEnd-nStart
//remember to repair this line, because of forum defect!
   cStr := s_ubstr(cStr, nStart, nEnd-nStart)
   
   return cStr
User avatar
IMATECH
Posts: 188
Joined: Sun May 27, 2012 9:33 pm
Location: Brazil: Goiânia-GO.

MXML Help

Post by IMATECH »

Hi Rathinagiri !

I spect this code can help you :-)

Regards

Code: Select all


#include "hbmxml.ch"

STATIC s_mxml_error := .F.
STATIC s_mxml_error_msg := ""

// *---------------------------------------------------------------------------*
// MR_Read_XML( cXML ) 
// cXML = FileName_XML
// *---------------------------------------------------------------------------*
FUNCTION MR_Read_XML( cXML )

   LOCAL oXml
   LOCAL bRet := .T.
   LOCAL aXml := ARRAY( 10 )

   mxmlSetErrorCallback( @MR_mxmlError() )

   oXml := mxmlLoadString( oXml, cXML, MXML_OPAQUE_CALLBACK )

   IF !( s_mxml_error )

      // *---------------------------------------------------------------------------*
      // text
      // *---------------------------------------------------------------------------*
      IF !( Empty( aXml[ 1 ] := mxmlFindElement( oXml, oXml, "text", NIL, NIL, MXML_DESCEND ) ) )
         aXml[ 2 ] := mxmlGetOpaque( aXml[ 1 ] )
         msginfo( aXml[ 2 ], aXml[ 2 ] )
      ENDIF
      
      // WORKING WITH NODES
      //
      // aXml[ 2 ] := mxmlGetFirstChild( aXml[ 1 ] )
      // WHILE !( Empty( aXml[ 2 ] ) )
      //   IF mxmlGetType( aXml[ 2 ] ) == MXML_ELEMENT
      //      aXml[ 3 ] := mxmlGetElement( aXml[ 2 ] )
      //      IF aXml[ 3 ] == 'text'
      //         aXml[ 4 ] := mxmlGetOpaque( aXml[ 2 ] )
      //         msginfo( aXml[ 4 ], aXml[ 4 ] )
      //     ENDIF
      //   ENDIF
      //   aXml[ 2 ] := mxmlGetNextSibling( aXml[ 1 ] )
      // ENDDO
      
   ENDIF
   
   oXml := NIL

   RETURN( bRet )

// *---------------------------------------------------------------------------*
// MR_mxmlError( cErrorMsg )
// *---------------------------------------------------------------------------*
STATIC PROCEDURE MR_mxmlError( cErrorMsg )

   s_mxml_error_msg := cErrorMsg
   s_mxml_error := .T.

   RETURN

M., Ronaldo

By: IMATECH

Imation Tecnologia
User avatar
mol
Posts: 3720
Joined: Thu Sep 11, 2008 5:31 am
Location: Myszków, Poland
Contact:

Re: MXML Help

Post by mol »

Hi guys!

I've spent whole day for searching solution for bad reading text elements value by hbmxml library.
I've studied harbour sources contrib\hbmxml\3rd\minixml\mxml_fil.c file.
Two lines are responsible for stopping reading text value when space, tab, new line character is reached.
I've modified and now it works OK.
changed lines:
1455: if ((ch == '<' ||
(mxml_isspace(ch) && type != MXML_OPAQUE && type != MXML_CUSTOM && type != MXML_TEXT)) &&
bufptr > buffer)


2044: else if (type == MXML_OPAQUE || type == MXML_CUSTOM ||( ( type == MXML_TEXT && !mxml_isspace(ch)) ||ch == ' ') || !mxml_isspace(ch))

I'm attaching modified library for all who need XML and want to test it.
Attachments
libmxml.zip
(22.41 KiB) Downloaded 382 times
User avatar
Rathinagiri
Posts: 5471
Joined: Tue Jul 29, 2008 6:30 pm
DBs Used: MariaDB, SQLite, SQLCipher and MySQL
Location: Sivakasi, India
Contact:

Re: MXML Help

Post by Rathinagiri »

A longtime wish! Now came true! Thank you Marek.

I think you can post this bugfix to the Harbour Team to get rectified.
East or West HMG is the Best.
South or North HMG is worth.
...the possibilities are endless.
Post Reply