Page 1 of 2

MXML Help

Posted: Thu Oct 13, 2011 6:18 pm
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?

Re: MXML Help

Posted: Fri Oct 14, 2011 4:52 am
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   


Re: MXML Help

Posted: Thu Aug 28, 2014 12:50 pm
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?

Re: MXML Help

Posted: Thu Aug 28, 2014 2:55 pm
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.

Re: MXML Help

Posted: Thu Aug 28, 2014 5:28 pm
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

Re: MXML Help

Posted: Fri Aug 29, 2014 7:36 am
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 :(

Re: MXML Help

Posted: Fri Aug 29, 2014 9:51 am
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

MXML Help

Posted: Sat Aug 30, 2014 3:42 am
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


Re: MXML Help

Posted: Thu Oct 16, 2014 11:41 am
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.

Re: MXML Help

Posted: Thu Oct 16, 2014 2:13 pm
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.