how XML extract tags, keys
Moderator: Rathinagiri
- dragancesu
- Posts: 931
- Joined: Mon Jun 24, 2013 11:53 am
- DBs Used: DBF, MySQL, Oracle
- Location: Subotica, Serbia
how XML extract tags, keys
I have XML files, see structure but how (easy) extract some tags, keys or other data
examle data in attcahment
examle data in attcahment
- Attachments
-
- efaktura.zip
- (290.95 KiB) Downloaded 336 times
Re: how XML extract tags, keys
Take a look at this sample, it might be useful to you.dragancesu wrote: ↑Tue Dec 21, 2021 11:19 am I have XML files, see structure but how (easy) extract some tags, keys or other data
examle data in attcahment
- dragancesu
- Posts: 931
- Joined: Mon Jun 24, 2013 11:53 am
- DBs Used: DBF, MySQL, Oracle
- Location: Subotica, Serbia
Re: how XML extract tags, keys
@edk Thank you, nice
this is for eInvoice goverment project, xml download from site and task is load into invoice data structure
Is posible something like in attachment
1. step xml_vadi
2. step xml_fnc
and result is DBF with data from XML
this is for eInvoice goverment project, xml download from site and task is load into invoice data structure
Is posible something like in attachment
1. step xml_vadi
2. step xml_fnc
and result is DBF with data from XML
- Attachments
-
- efaktura2.zip
- (5.7 KiB) Downloaded 180 times
Re: how XML extract tags, keys
It seems to me that a better solution will be to directly process the xml file and save the read values directly to the target databases. Here is an example:dragancesu wrote: ↑Wed Dec 22, 2021 8:22 am @edk Thank you, nice
this is for eInvoice goverment project, xml download from site and task is load into invoice data structure
Is posible something like in attachment
1. step xml_vadi
2. step xml_fnc
and result is DBF with data from XML
Code: Select all
#require "hbmxml.hbc"
#include "hmg.ch"
#define cTab Chr ( 9 )
Function Main
Local cXmlString, cXmlFile, aXML, i, cPath, cKey, xValue, hAttrib, lShowMessage
//To Make DO CASE ... sequence only
Local aPath, Attrib_Key
cXmlFile := GetFile( {{'XML File', '*.xml'}}, 'Select XML', hb_CWD(), .F. , .T. )
IF EMPTY( cXmlFile )
RETURN Nil
ENDIF
lShowMessage := MsgYesNo( "Show processed data?" )
cXmlString := FileStr( cXmlFile )
aXML := hb_XmlToArray( cXmlString, .T. /* .F. = encode root node also */ )
//To Make DO CASE ... sequence only
aPath :={}
STRFILE ("****** DO CASE for the " + hb_FNameNameExt ( cXmlFile ) + " file structure ********" + CRLF + "DO CASE" + CRLF, "Do_case.prg", .F. )
//
FOR i := 1 TO Len ( aXML )
cPath := aXML [ i ] [ 1 ]
cKey := aXML [ i ] [ 2 ]
xValue := aXML [ i ] [ 3 ]
hAttrib := aXML [ i ] [ 4 ]
// <---- here is xml data processing, e.g. writing to databases according to tags and possibly attributes
IF lShowMessage
/* In this example, I'm displaying the read values, the key and the path to the key along with any attributes */
MsgInfo ('Key Path: "' + cPath + '"' + CRLF + CRLF + ;
'Key: "' + cKey + '"' + CRLF + CRLF + ;
"Value: " + Left ( xValue, 100 ) /* first 100 chars for test only */ + CRLF + CRLF +;
IF( Len( hAttrib ) > 0 , "Attribute(s): " + hb_JsonEncode ( hAttrib ), "" ), "Processing data from an XML file." )
ENDIF
/* Below I used the read XML file structure to generate a DO CASE ... sequence that I can use to process data from the XML file, e.g. to write values to the appropriate database fields. */
//Make DO CASE ... sequence
IF hb_AScan ( aPath, cPath + "/" + cKey, , , .T. ) = 0
AAdd( aPath, cPath + "/" + cKey)
STRFILE ( cTab + 'CASE cKey == "' + cKey + '" .AND. cPath == "' + cPath + '"' + CRLF + cTab + cTab + CRLF , "Do_case.prg", .T. )
IF LEN( hAttrib ) > 0
FOR EACH Attrib_Key IN hb_HKeys ( hAttrib )
STRFILE ( cTab + cTab + 'IF hb_HHasKey( hAttrib, "' + Attrib_Key + '" )' + CRLF + ;
cTab + cTab + cTab + 'xAttribValue := hb_HGet ( hAttrib, "' + Attrib_Key + '" )' + CRLF + CRLF + ;
cTab + cTab + 'ENDIF' + CRLF + CRLF , "Do_case.prg", .T. )
NEXT
ENDIF
ENDIF
//End Make DO CASE ... sequence
NEXT i
STRFILE ("END CASE", "Do_case.prg", .T. )
MsgInfo ('The file "Do_case.prg" has been created with the DO CASE sequence for the "' + hb_FNameNameExt ( cXmlFile ) + '" file structure.' )
Return
*****************************************************************************
STATIC FUNCTION hb_XMLtoArray( cXML, lOmitHeader )
LOCAL pXML
Private __aXML := {}
hb_default( @lOmitHeader, .T. )
pXML := mxmlLoadString( NIL, hb_utf8ToStr( cXML ), MXML_OPAQUE_CALLBACK )
IF !Empty( pXML )
IF lOmitHeader
hb_ArrayXML_getnodes( mxmlGetFirstChild( pXML ))
ELSE
hb_ArrayXML_getnodes( pXML )
ENDIF
ENDIF
mxmlDelete( pXML )
RETURN __aXML
*****************************************************************************
STATIC FUNCTION hb_ArrayXML_getnodes( pNode )
LOCAL cKey, pChild, xResult, xValue, cPrevKey, hAttrib, pParrentNode, cPath
DO WHILE !Empty( pNode )
IF mxmlGetType( pNode ) == MXML_ELEMENT
cKey := mxmlGetElement( pNode )
pChild := mxmlGetFirstChild( pNode )
xValue := hb_ArrayXML_getnodes( pChild )
IF xValue == NIL
xValue := mxmlGetOpaque( pNode )
IF !( xValue == CRLF )
cPath := ""
pParrentNode := mxmlGetParent( pNode )
DO WHILE !EMPTY ( pParrentNode )
cPrevkey := mxmlGetElement( pParrentNode )
IF Left ( cPrevkey, 4 ) <> "?xml"
cPath := cPrevkey + IF( !Empty( cPath ), "/", "") + cPath
ENDIF
pParrentNode := mxmlGetParent( pParrentNode )
ENDDO
hAttrib := hb_mxmlGetAttrs( pNode )
AADD( __aXML, { cPath, cKey, xValue, hAttrib } )
xResult := __aXML
ENDIF
ENDIF
ENDIF
pNode := mxmlGetNextSibling( pNode )
ENDDO
RETURN xResult
In my example, the read paths, keys, values and attributes were used to generate a DO CASE sequence that I can use in .prg to process the read data from the XML file.
I think that this procedure can be used with any structure of XML files, but you need to pay attention to use an xml file when creating a DO CASE sequence, in which all possible keys described in the schema are contained in the structure, including the optional ones.
- dragancesu
- Posts: 931
- Joined: Mon Jun 24, 2013 11:53 am
- DBs Used: DBF, MySQL, Oracle
- Location: Subotica, Serbia
Re: how XML extract tags, keys
Thank you
Re: how XML extract tags, keys
Added CDATA support:
Code: Select all
#require "hbmxml.hbc"
#include "hmg.ch"
#define cTab Chr ( 9 )
Function Main
Local cXmlString, cXmlFile, aXML, i, cPath, cKey, xValue, hAttrib, lShowMessage := .T.
//To Make DO CASE ... sequence only
Local aPath, Attrib_Key
cXmlFile := GetFile( {{'XML File', '*.xml'}}, 'Select XML', hb_CWD(), .F. , .T. )
IF EMPTY( cXmlFile )
RETURN Nil
ENDIF
lShowMessage := MsgYesNo( "Show processed data?" )
cXmlString := FileStr( cXmlFile )
aXML := hb_XmlToArray( cXmlString, .T. /* .F. = encode root node also */ )
//To Make DO CASE ... sequence only
aPath :={}
STRFILE ("****** DO CASE for the " + hb_FNameNameExt ( cXmlFile ) + " file structure ********" + CRLF + "DO CASE" + CRLF, "Do_case.prg", .F. )
//
FOR i := 1 TO Len ( aXML )
cPath := aXML [ i ] [ 1 ]
cKey := aXML [ i ] [ 2 ]
xValue := aXML [ i ] [ 3 ]
hAttrib := aXML [ i ] [ 4 ]
// <---- here is xml data processing, e.g. writing to databases according to tags and possibly attributes
IF lShowMessage
/* In this example, I'm displaying the read values, the key and the path to the key along with any attributes */
MsgInfo ('Key Path: "' + cPath + '"' + CRLF + CRLF + ;
'Key: "' + cKey + '"' + CRLF + CRLF + ;
"Value: " + Left ( xValue, 100 ) /* first 100 chars for test only */ + CRLF + CRLF +;
IF( Len( hAttrib ) > 0 , "Attribute(s): " + hb_JsonEncode ( hAttrib ), "" ), "Processing data from an XML file." )
ENDIF
/* Below I used the read XML file structure to generate a DO CASE ... sequence that I can use to process data from the XML file, e.g. to write values to the appropriate database fields. */
//Make DO CASE ... sequence
IF hb_AScan ( aPath, cPath + "/" + cKey, , , .T. ) = 0
AAdd( aPath, cPath + "/" + cKey)
STRFILE ( cTab + 'CASE cKey == "' + cKey + '" .AND. cPath == "' + cPath + '"' + CRLF + cTab + cTab + CRLF , "Do_case.prg", .T. )
IF LEN( hAttrib ) > 0
FOR EACH Attrib_Key IN hb_HKeys ( hAttrib )
STRFILE ( cTab + cTab + 'IF hb_HHasKey( hAttrib, "' + Attrib_Key + '" )' + CRLF + ;
cTab + cTab + cTab + 'xAttribValue := hb_HGet ( hAttrib, "' + Attrib_Key + '" )' + CRLF + CRLF + ;
cTab + cTab + 'ENDIF' + CRLF + CRLF , "Do_case.prg", .T. )
NEXT
ENDIF
ENDIF
//End Make DO CASE ... sequence
NEXT i
STRFILE ("END CASE", "Do_case.prg", .T. )
MsgInfo ('The file "Do_case.prg" has been created with the DO CASE sequence for the "' + hb_FNameNameExt ( cXmlFile ) + '" file structure.' )
Return
*****************************************************************************
STATIC FUNCTION hb_XMLtoArray( cXML, lOmitHeader )
LOCAL pXML
Private __aXML := {}
hb_default( @lOmitHeader, .T. )
pXML := mxmlLoadString( NIL, hb_utf8ToStr( cXML ), MXML_OPAQUE_CALLBACK )
IF !Empty( pXML )
IF lOmitHeader
hb_ArrayXML_getnodes( mxmlGetFirstChild( pXML ))
ELSE
hb_ArrayXML_getnodes( pXML )
ENDIF
ENDIF
mxmlDelete( pXML )
RETURN __aXML
*****************************************************************************
STATIC FUNCTION hb_ArrayXML_getnodes( pNode )
LOCAL cKey, pChild, xResult, xValue, cPrevKey, hAttrib, pParrentNode, cPath
DO WHILE !Empty( pNode )
IF mxmlGetType( pNode ) == MXML_ELEMENT
cKey := mxmlGetElement( pNode )
pChild := mxmlGetFirstChild( pNode )
xValue := hb_ArrayXML_getnodes( pChild )
IF xValue == NIL
xValue := mxmlGetOpaque( pNode )
IF !(xValue == CRLF)
cPath := ""
pParrentNode := mxmlGetParent( pNode )
IF Left ( cKey, 8 ) == "![CDATA["
xValue := hb_StrShrink ( mxmlGetCDATA( pNode ), 2 )
cKey := mxmlGetElement( mxmlGetParent( pNode ) )
pParrentNode := mxmlGetParent( mxmlGetParent( pNode ) )
ENDIF
DO WHILE !EMPTY ( pParrentNode )
cPrevkey := mxmlGetElement( pParrentNode )
IF Left ( cPrevkey, 4 ) <> "?xml"
cPath := cPrevkey + IF( !Empty( cPath ), "/", "") + cPath
ENDIF
pParrentNode := mxmlGetParent( pParrentNode )
ENDDO
hAttrib := hb_mxmlGetAttrs( pNode )
AADD( __aXML, { cPath, cKey, xValue, hAttrib } )
xResult := __aXML
ENDIF
ENDIF
ENDIF
pNode := mxmlGetNextSibling( pNode )
ENDDO
RETURN xResult
-
brunellopulix
- Posts: 80
- Joined: Sat Apr 24, 2010 10:17 am
Re: how XML extract tags, keys
Hi
if you find it useful here a procedure that converts xml to Ini
FUNCTION _Xml_To_Ini3(cXml,cIni)
LOCAL aRay := {}
LOCAL aTemp := {}
LOCAL cString := hb_MemoRead(cXml)
LOCAL i
Local nhandle
*
cString := StrTran(cString,'<',CHR(10)+'<')
cString := StrTran(cString,'>','>'+CHR(10))
cString := StrTran(cString,CHR(13),'')
aTemp := hb_ATokens(cString,CHR(10))
*
nHandle := FCreate(cIni)
FOR i := 1 TO Len(aTemp)
IF Empty(aTemp)
If !Empty(aRay) .and. Left(aRay[1],2) != '</'
aRay[1] := StrTran(aRay[1],'<','[')
aRay[1] := StrTran(aRay[1],'>',']')
FWrite(nHandle,CRLF)
FWrite(nHandle,aRay[1]+CRLF)
Endif
aRay := {}
else
aadd(aRay,AllTrim(aTemp))
If Len(aRay) == 3
aRay[1] := StrTran(aRay[1],'<','')
aRay[1] := StrTran(aRay[1],'>','')
FWrite(nHandle,aRay[1]+'='+aRay[2]+CRLF)
aRay := {}
Endif
Endif
Next
*
FClose(nHandle)
execute file cIni
*
RETURN
Brunello Pulix
if you find it useful here a procedure that converts xml to Ini
FUNCTION _Xml_To_Ini3(cXml,cIni)
LOCAL aRay := {}
LOCAL aTemp := {}
LOCAL cString := hb_MemoRead(cXml)
LOCAL i
Local nhandle
*
cString := StrTran(cString,'<',CHR(10)+'<')
cString := StrTran(cString,'>','>'+CHR(10))
cString := StrTran(cString,CHR(13),'')
aTemp := hb_ATokens(cString,CHR(10))
*
nHandle := FCreate(cIni)
FOR i := 1 TO Len(aTemp)
IF Empty(aTemp)
If !Empty(aRay) .and. Left(aRay[1],2) != '</'
aRay[1] := StrTran(aRay[1],'<','[')
aRay[1] := StrTran(aRay[1],'>',']')
FWrite(nHandle,CRLF)
FWrite(nHandle,aRay[1]+CRLF)
Endif
aRay := {}
else
aadd(aRay,AllTrim(aTemp))
If Len(aRay) == 3
aRay[1] := StrTran(aRay[1],'<','')
aRay[1] := StrTran(aRay[1],'>','')
FWrite(nHandle,aRay[1]+'='+aRay[2]+CRLF)
aRay := {}
Endif
Endif
Next
*
FClose(nHandle)
execute file cIni
*
RETURN
Brunello Pulix
Re: how XML extract tags, keys
Hola EDK
Muchas gracias por tu aporte, le veo mucha utilidad.
He estado haciendo pruebas pero ya me perdí, y "necesito una una pequeña ayuda de mis amigos".
Los datos que están en Amarillo si los puedo obtener pero los que están en Azul no logro hacerlo.
Trate de hacerlo con el DO_CASE que genera tu ejemplo pero tampoco resultó.
Alguna idea ?
*-------------------------------------------------------------------------------------------------------------------------
Hi EDK
Thank you very much for your contribution, I see it very useful.
I've been doing tests but I'm lost, and "I need a little help from my friends."
I can get the data that are in Yellow but the ones that are in Blue I can't.
I tried to do it with the DO_CASE that your example generates but it didn't work either.
Any ideas ?
Pueden agrandar la imagen abriéndola en otra pestaña.
*---------------------------------------------------------------------
The image can be enlarged by opening it in another tab.
Muchas gracias por tu aporte, le veo mucha utilidad.
He estado haciendo pruebas pero ya me perdí, y "necesito una una pequeña ayuda de mis amigos".
Los datos que están en Amarillo si los puedo obtener pero los que están en Azul no logro hacerlo.
Trate de hacerlo con el DO_CASE que genera tu ejemplo pero tampoco resultó.
Alguna idea ?
*-------------------------------------------------------------------------------------------------------------------------
Hi EDK
Thank you very much for your contribution, I see it very useful.
I've been doing tests but I'm lost, and "I need a little help from my friends."
I can get the data that are in Yellow but the ones that are in Blue I can't.
I tried to do it with the DO_CASE that your example generates but it didn't work either.
Any ideas ?
Pueden agrandar la imagen abriéndola en otra pestaña.
*---------------------------------------------------------------------
The image can be enlarged by opening it in another tab.
Andrés González López
Desde Guadalajara, Jalisco. México.
Desde Guadalajara, Jalisco. México.
Re: how XML extract tags, keys
At first glance it looks like some nodes have Nil values but have attributes and child node. Those with Nil values are ignored, so we will have to treat them as if they had empty values. I'll try to prepare something tomorrow.
-
brunellopulix
- Posts: 80
- Joined: Sat Apr 24, 2010 10:17 am
Re: how XML extract tags, keys
This is the attachment
Brunello Pulix