local loWebService, ; lcXML, ; loXMLAdapter as XMLAdapter close databases all set multilocks on * Simulate calling a Web Service to get some data. loWebService = createobject('WebService') lcXML = loWebService.GetCustomerByID('ALFKI') * Create a cursor from the retrieved XML. loXMLAdapter = createobject('XMLAdapter') loXMLAdapter.LoadXML(lcXML) loXMLAdapter.Tables.Item(1).ToCursor(.F., 'Customers') * Make any changes desired. select Customers cursorsetprop('Buffering', 5) messagebox("Here's the ALFKI customer retrieved from a simulated Web " + ; 'Service. Make whatever changes you wish (you can even add or delete ' + ; 'records), then press Ctrl+W to close the BROWSE window and save the ' + ; 'changes back to the Web Service. ' + chr(13) + chr(13) + ; 'Try blanking the CUST_ID or COMPANY fields, changing COUNTRY to ' + ; '"Canada", or adding a record with the same CUST_ID as an existing ' + ; 'record (try "BERGS", for example) and see what happens when you save.', ; 0, 'XMLAdapter Example') browse * Now write changes back to the Web Service if there are any. if getnextmodified(0) <> 0 * We need to handle blank non-character fields (see comments in the CleanData * procedure below). do CleanData * Clean out the XMLAdapter first. with loXMLAdapter .ReleaseXML(.T.) .Tables.Remove(-1) * Attach the Customers cursor to it. .AddTableSchema('Customers') * Set some properties and flags for the ToXML method, then generate a diffgram * from the cursor. .UTF8Encoded = .T. && cursor contains international characters .IsDiffgram = .T. && Generate an XML DiffGram lcSchemaLocation = '' && Our schema is inline llIsFile = .F. && Our XML is a stream llIncludeBefore = .T. && Include <diffgram:before> format llChangesOnly = .T. && Generate only changes we made .ToXML('lcXML', lcSchemaLocation, llIsFile, llIncludeBefore, ; llChangesOnly) endwith * Display the diffgram. strtofile(lcXML,'Test.txt') messagebox("Here's the diffgram the XMLAdapter created that'll be " + ; 'sent back to the Web Service to update the data source.', 0, ; 'XMLAdapter Example') modify file Test.txt erase Test.txt * Send the diffgram to the Web Service and display the results. lcResults = loWebService.UpdateCustomer(lcXML) if empty(lcResults) messagebox('The Web Service indicated that the update was ' + ; 'successful.', 0, 'XMLAdapter Example') else messagebox('The Web Service indicated that the update was ' + ; 'unsuccessful. The message from the Web Service is:' + chr(13) + ; chr(13) + lcResults, 0, 'XMLAdapter Example') endif empty(lcResults) endif getnextmodified(0) <> 0 close databases all * Because of the way VFP works, fields in a new record are "blank" rather than * containing the proper "empty" value for their data type. This will cause an * error when the XMLAdapter in the Web Service tries to load the XML because * non-character fields will have an invalid value. procedure CleanData local laFields[1], ; lnFields, ; lnI, ; lcField, ; lcType lnFields = afields(laFields) scan for lnI = 1 to lnFields lcField = laFields[lnI, 1] lcType = laFields[lnI, 2] do case case not isblank(&lcField) case lcType = 'L' replace (lcField) with .F. case lcType $ 'NFIBY' replace (lcField) with 0 case lcType $ 'DT' replace (lcField) with {} endcase next lnI endscan return * This class simulates a Web Service: it both returns a customer record as XML * and accepts a diffgram to make changes to the data. define class WebService as Session procedure Init set multilocks on open database (_samples + 'Data\TestData') endproc procedure Destroy close database endproc * Get the customer record for the specified ID and return it as XML. procedure GetCustomerByID(CustomerID as String) as String local lcXML select * from Customer where Cust_ID = ?CustomerID into cursor _Temp cursortoxml('_Temp', 'lcXML', 1, 0, 0, '1') use use in Customer return lcXML endproc * Accept a diffgram and try to apply it to the Customer table. procedure UpdateCustomer(DiffGram as String) as String local lcMessage, ; loXMLAdapter as XMLAdapter, ; laError[1], ; loException as Exception * First load the diffgram into an XMLAdapter. Then, create a cursor from the * diffgram so we can do some business rules. lcMessage = '' loXMLAdapter = createobject('XMLAdapter') try loXMLAdapter.LoadXML(DiffGram) loXMLAdapter.Tables.Item(1).ToCursor(.F., '_Temp') select _Temp do case case empty(nvl(Cust_ID, '')) throw 'Customer ID cannot be blank or null.' case empty(nvl(Company, '')) throw 'Company name cannot be blank or null.' case upper(Country) = 'CANADA' throw "We don't want no stinking Canadians!" endcase use * Try to make the changes in the Customer table. use Customer cursorsetprop('Buffering', 5) begin transaction loXMLAdapter.Tables.Item(1).ApplyDiffgram('Customer') if not tableupdate(.T.) aerror(laError) throw laError[2] endif not tableupdate(.T.) end transaction messagebox('This is what the Customer table looks like after ' + ; 'the diffgram was applied.', 0, 'Simulated Web Service') browse * If an error occurred (either a VFP error or one we raised), rollback the * transaction if we have one and get the error message to return. catch to loException if txnlevel() > 0 rollback endif txnlevel() > 0 if loException.ErrorNo = 2071 lcMessage = loException.UserValue else lcMessage = loException.Message endif loException.ErrorNo = 2071 * Close any tables we opened. finally use in select('_Temp') use in select('Customer') endtry return lcMessage endproc enddefine