Sponsored Link •
|
Summary
As a followup to "Simplifying XML Manipulation", here is the Fedex Rate Requester that motivated me to make xmlnode in the first place. Because xmlnode got the XML-creation code noise out of the way, I was able to bash this together very quickly.
Advertisement
|
As people pointed out for that post, xmlnode does not handle XML namespaces. However, I have not had to deal with those yet; I've only needed to create XML and throw it at some application. If I run into a namespace problem, I'll either adapt xmlnode or move to some other system that handles them, like py.xml.
One thought occurred to me while I was building the rate requester: it's not uncommon that the documentation for the service you're using will give example XML showing what you should generate. It would be interesting to modify xmlnode so that it would parse existing XML and generate the code necessary to build that XML. This could speed up the development process and possibly eliminate mistakes.
Note that the FedexRateRequest class inherits Node, and inheritance (rather than composition) is useful here. Also, in the getRates() function, the copy.deepcopy() function is used to clone FedexRateRequest objects, eliminating duplicated effort.
Although I was able to put this code together quickly, I did depend on the code and information that I found at http://opensource.pseudocode.net/files/shipping.tgz , which definitely helped me bootstrap the process. Look at that package to find out how to get your own meter number.
import sys, urllib, copy from xml.dom.minidom import parseString from xmlnode import Node class FedexRateRequest(Node): login = { "account" : "your account #", "meter" : "your meter #" } def __init__(self, service, packaging, weight, orginState, originZip, destState, destZip): self.Error = False if float(weight) > 1.0 and packaging == 'FEDEXENVELOPE': # Can't be more than 1 lb. packaging = 'FEDEXBOX' Node.__init__(self, "FDXRateRequest") self.setAttribute("xmlns:api", "http://www.fedex.com/fsmapi") self.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance") self.setAttribute("xsi:noNamespaceSchemaLocation", "FDXRateRequest.xsd") self += Node("RequestHeader") + \ Node("AccountNumber", FedexRateRequest.login["account"]) + \ Node("MeterNumber", FedexRateRequest.login["meter"]) + \ Node("CarrierCode", "FDXE") self += Node("Service", service) self += Node("Packaging", packaging) self += Node("WeightUnits", 'LBS') self += Node("Weight", weight) self += Node("OriginAddress") + Node("StateOrProvinceCode", orginState) + \ Node("PostalCode", originZip) + Node("CountryCode", "US") self += Node("DestinationAddress") + Node("StateOrProvinceCode", destState) + \ Node("PostalCode", destZip) + Node("CountryCode", "US") self += Node("Payment") self += Node("PackageCount", "1") self.result = None def requestRate(self): reqxml = '<?xml version="1.0" ?>' + self.rawxml().strip() result = urllib.urlopen("https://gateway.fedex.com/GatewayDC", reqxml).read() self.result = Node.create(parseString(result)) if result.find("Error") != -1: self.Error = True return self.base = float(self.result["BaseCharge"].value) self.discount = float(self.result["TotalDiscount"].value) self.surcharge = float(self.result["TotalSurcharge"].value) self.netcharge = float(self.result["NetCharge"].value) def showResults(self): print self["Service"].value, self["Packaging"].value if self.Error: print "Error:", self.result["Message"].value return print "base:", self.base print "discount:", self.discount print "surcharge:", self.surcharge print "net charge:", self.netcharge def getRates(packaging, weight, orginState, originZip, destState, destZip, homedelivery): priority = FedexRateRequest('PRIORITYOVERNIGHT', packaging, weight, orginState, originZip, destState, destZip) standard = copy.deepcopy(priority) standard["Service"].value = 'STANDARDOVERNIGHT' twoday = copy.deepcopy(priority) twoday["Service"].value = 'FEDEX2DAY' ground = copy.deepcopy(priority) ground["CarrierCode"].value = 'FDXG' ground["Packaging"].value = 'YOURPACKAGING' # Ground must use YOURPACKAGING if homedelivery: ground["Service"].value = 'GROUNDHOMEDELIVERY' else: ground["Service"].value = 'FEDEXGROUND' priority.requestRate() standard.requestRate() twoday.requestRate() ground.requestRate() return (ground, twoday, standard, priority) if __name__ == "__main__": for rate in getRates('1.6', "CA", "91941", "CO", "81224", homedelivery=False): rate.showResults()
Have an opinion? Be the first to post a comment about this weblog entry.
If you'd like to be notified whenever Bruce Eckel adds a new entry to his weblog, subscribe to his RSS feed.
Bruce Eckel (www.BruceEckel.com) provides development assistance in Python with user interfaces in Flex. He is the author of Thinking in Java (Prentice-Hall, 1998, 2nd Edition, 2000, 3rd Edition, 2003, 4th Edition, 2005), the Hands-On Java Seminar CD ROM (available on the Web site), Thinking in C++ (PH 1995; 2nd edition 2000, Volume 2 with Chuck Allison, 2003), C++ Inside & Out (Osborne/McGraw-Hill 1993), among others. He's given hundreds of presentations throughout the world, published over 150 articles in numerous magazines, was a founding member of the ANSI/ISO C++ committee and speaks regularly at conferences. |
Sponsored Links
|