|
|
|
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
|