Hi Diego;
Here is a snippet from my code that does a Vehicle ID lookup on a Vin Decoder website using XML.
I pass it a record object from several of my other functions.
I create and post an xml request string and DataOne returns an xml document.
The creation of the xml post string is simple code creating a text body (cBody). I add a CRLF after
each line to make it more readable during debugging.
You can use TEXT/ENDTEXT probably as well but I like the flexibility to access and insert vars in the creation of
the document.
I then use xb2net functions to create and post this string but I understand standard xBase++ can now do this as well.
I then use Rogers DC_XML functions and methods to parse the returned xml document.
DC_XML2OBJECTTREE(cString) creates an object that can be parsed using findnode,attr, and content methods.
It's great stuff. You will probably want to put a lot of validation in your code to test the valtypes of each returned
value to check to see if it is an object and if the content of that object is a character string. When necessary,
numeric data should be created using the val(cVal) function to match your database structure.
The code is below. Let me know if you have any questions.
*-------------------function to Retrieve Decoded Vin from DataOne for Credit App system ----------------------*
function vindecoderCA(oAceVehic) /// oAceVehic is a record object being passed from the calling function.
local GETLIST:={}, GETOPTIONS, oHttp,oResp,cXml,cBody:='',oForm ,xStatus,oRootnode,oTrim ,bPreError,oError
LOCAL oDecode,oQuery,oResponse,oMarket,oCommon,oBasic,oYear,oMake,oModel,oDoors,oDrive,oEngine,oEngines,;
oCylinders,oDisplace,oTrans,oTransmission,oType,oGears,oValue,cValue:='' , oStyle, aSpecs ,oSpecification
LOCAL oInstalledEquip,oOptionalEquip,aCategory:={},cCatname:='',cComment:='',aEquipment:={},i,j,cEquipname,cXmlData:=''
DCGETOPTIONS SAYWIDTH 0 SAYFONT '10.Courier New' GETFONT '10.Courier New' autoresize
/// if vin is empty- ask for it.
IF EMPTY(oAceVehic:Vin)
@ 10,0 DCSAY 'Enter Vin to Decode' get oAceVehic:Vin VALID{|| CHECKDIGIT(oAceVehic:Vin)}
DCREAD GUI TO XSTATUS ENTEREXIT BUTTONS 2 TITLE 'Vin Decoder'
endif
/// open VINDECODES DBF
IF UseDB({'VINDECODES'})
VINDECODES->(DBGOTOP())
ELSE
DC_WINALERT('Decoder file not available')
RETURN NIL
ENDIF
/// VALIDATE FOR A VALID VEHICLE ID
IF !CHECKDIGIT(oAceVehic:Vin)
DC_WINALERT('This is NOT a valid Vin!')
RETURN NIL
ENDIF
/// CREATE xml string - simply keep adding tags to cBody to construct the document. CRLF is a Carriage Return Line Feed that makes it easier to read.
/// this xml document conforms to what DataOne wants as an XML request.
SELECT VINDECODES
IF !VINDECODES->(DBSEEK(oAceVehic:Vin))
cBody:=cBody+'<?xml version="1.0" encoding="UTF-8"?>'+CRLF
cBody:=cBody+'<decoder_query>'+CRLF
cBody:=cBody+'<decoder_settings>'+CRLF
cBody:=cBody+'<display>full</display>'+CRLF
cBody:=cBody+'<styles>on</styles>'+CRLF
cBody:=cBody+'<style_data_packs>'+CRLF
cBody:=cBody+'<basic_data>on</basic_data>'+CRLF
cBody:=cBody+'<pricing>off</pricing>'+CRLF
cBody:=cBody+'<engines>on</engines>'+CRLF
cBody:=cBody+'<transmissions>on</transmissions>'+CRLF
cBody:=cBody+'<specifications>on</specifications>'+CRLF
cBody:=cBody+'<installed_equipment>on</installed_equipment>'+CRLF
cBody:=cBody+'<optional_equipment>on</optional_equipment>'+CRLF
cBody:=cBody+'<generic_optional_equipment>on</generic_optional_equipment>'+CRLF
cBody:=cBody+'<colors>on</colors>'+CRLF
cBody:=cBody+'<warranties>off</warranties>'+CRLF
cBody:=cBody+'<fuel_efficiency>off</fuel_efficiency>'+CRLF
cBody:=cBody+'<green_scores>off</green_scores>'+CRLF
cBody:=cBody+'<crash_test>off</crash_test>'+CRLF
cBody:=cBody+'</style_data_packs>'+CRLF
cBody:=cBody+'<common_data>on</common_data>'+CRLF
cBody:=cBody+'<common_data_packs>'+CRLF
cBody:=cBody+'<basic_data>on</basic_data>'+CRLF
cBody:=cBody+'<pricing>off</pricing>'+CRLF
cBody:=cBody+'<engines>on</engines>'+CRLF
cBody:=cBody+'<transmissions>on</transmissions>'+CRLF
cBody:=cBody+'<specifications>on</specifications>'+CRLF
cBody:=cBody+'<installed_equipment>on</installed_equipment>'+CRLF
cBody:=cBody+'<generic_optional_equipment>on</generic_optional_equipment>'+CRLF
cBody:=cBody+'</common_data_packs>'+CRLF
cBody:=cBody+'</decoder_settings>'+CRLF
cBody:=cBody+'<query_requests>'+ CRLF
cBody:=cBody+'<query_request identifier="'+oAceVehic:Vin+'">'+CRLF
cBody:=cBody+'<vin>'+oAceVehic:Vin+'</vin>'+CRLF
cBody:=cBody+'</query_request>'+CRLF
cBody:=cBody+'</query_requests>'+CRLF
cBody:=cBody+'</decoder_query>'+CRLF
///post to dataone
/// THESE ARE xB2Net functions
oHttp := xbHTTPClient():new()
oForm := xbForm():new()
oForm:SetVar("client_id", "xxxx")
oForm:SetVar("authorization_code", "xxxxxxxxxxxxxxxxxxxxxxxxxxxx ")
oForm:SetVar("decoder_query",cBody)
oResp := oHttp:Execute("
https://api.dataonesoftware.com/webserv ... OST",oForm)
// if it is empty
if oResp == NIL
MsgBox("Error:" + str(oHttp:ErrorCode) + chr(10) + oHttp:ErrorMessage)
RETURN NIL
endif
SELECT VINDECODES /// ADD TO FILE FOR FUTURE USE
IF VINDECODES->(DC_ADDREC())
REPLACE VINDECODES->VIN WITH oAceVehic:Vin
REPLACE VINDECODES->PULLDATE WITH DATE()
REPLACE VINDECODES->XMLDATA WITH alltrim(oResp:content)
ENDIF
cXmlData:=alltrim(oResp:content) /// CONVERT TO STRING
oRootNode := DC_Xml2ObjectTree(cXmlData) /// AND PARSE
IF !valtype(oRootNode)=='O'
DC_WinAlert('Could not open file. Invalid Data Return from Vin Decoder ')
RETURN FALSE
ENDIF
ELSE /// IF IT IS FOUND IN VINDECODES
cXmlData := ALLTRIM(VINDECODES->XMLDATA) ///LOAD STRING
/// parse the string using Roger Donnay's XML function
oRootnode:= DC_Xml2ObjectTree(cXMLDATA) //PARSE
ENDIF
VINDECODES->(DBCLOSEAREA()) /// CLOSE VINDECODES FILE
/// POST INTERIM ERROR HANDLER
bPreError := ErrorBlock( {|oError| _vindecodeErrorBlock(oError)})
BEGIN SEQUENCE
// if oRootnode is not a valid object RETURN
IF !VALTYPE(oRootnode)=='O'
DC_WINALERT('Vin Decode not available for this vehicle')
RETURN NIL
ENDIF
/// NOW TEST FOR OTHER NODES
oDecode:=oRootnode:findnode('decoded_data')
IF !valtype(oDecode) = 'O'
DC_WINALERT('No Decoder Info available on this vehicle.')
RETURN NIL
endif
oQuery:=oDecode:findnode('query_responses')
IF !valtype(oQuery) = 'O'
DC_WINALERT('No Decoder Info available on this vehicle.')
RETURN NIL
endif
oResponse:=oQuery:findnode('query_response')
IF !valtype(oResponse) = 'O'
DC_WINALERT('No Decoder Info available on this vehicle.')
RETURN NIL
endif
oMarket:=oResponse:findnode('us_market_data')
IF !valtype(oMarket) = 'O'
DC_WINALERT('No Decoder Info available on this vehicle.')
RETURN NIL
endif
oCommon:=oMarket:findnode('us_styles')
IF !valtype(oCommon) = 'O'
DC_WINALERT('No Decoder Info available on this vehicle.')
RETURN NIL
endif
oStyle:=oCommon:findnode('style')
IF !VALTYPE(oStyle) == 'O'
DC_WINALERT('Vin Decode not available for this vehicle')
RETURN NIL
ENDIF
oBasic:=oStyle:findnode('basic_data')
IF !VALTYPE(oBasic) == 'O'
DC_WINALERT('Vin Decode not available for this vehicle')
RETURN NIL
ENDIF
/// POPULATE oAceVehic with data extracted from above
oYear:=oBasic:findnode('year')
oAceVehic:year:=oYear:content
cComment:=cComment+oYear:content +CRLF
oMake:=oBasic:findnode('make')
oAceVehic:make:=oMake:content
oModel:=oBasic:findnode('model')
oAceVehic:model:=oModel:content
END SEQUENCE
ErrorBlock(bPreError)
return oAceVehic