-
Notifications
You must be signed in to change notification settings - Fork 1
/
DHLProcessor.m
288 lines (224 loc) · 9.96 KB
/
DHLProcessor.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
//
// DPDProcessor.m
//
//
// Created by Sandor Kolotenko on 03/03/2012.
// Copyright (c) 2012 Sandor Kolotenko. All rights reserved.
//
#import "Record.h"
#import "Parcel.h"
#import "HTMLParser.h"
#import "DHLProcessor.h"
@implementation DHLProcessor
- (id) init
{
// For internal reference only. Use as you wish.
// Originally this DHLProcessor class was a part of a larger app (including
// FedEx and Hungarian Post), these ID's required for compatibility reasons
// You may remove them.
name = @"DHL";
serviceID = 2;
return self;
}
//Flag for your internal reference.
- (BOOL)isServiceAvailable
{
return YES;
}
//Actual result parsing is done here. Call this method in background.
- (Parcel*)getDetails:(NSMutableData*)data
{
NSError *error = nil;
Parcel* consigment = [[Parcel alloc] init];
HTMLParser *parser = [[HTMLParser alloc] initWithData:data error:&error];
consigment.TrackingRecords = [[NSMutableArray alloc] init];
if (error) {
NSLog(@"Error: %@", error);
//Add additional error processing here.
return nil;
}
HTMLNode *bodyNode = [parser body];
HTMLNode* baseNode = [bodyNode findChildOfClass:@"shipmenttracking"];
HTMLNode* baseTable = [baseNode findChildTag:@"table"];
NSArray *rowNodes = [baseTable findChildTags:@"tr"];
//Parsing tracking number
HTMLNode* airWaybillSpan = [bodyNode findChildOfClass:@"air_waybill"];
if (airWaybillSpan != nil) {
NSRange semicolon = [[airWaybillSpan contents] rangeOfString:@":"];
if (semicolon.location != NSNotFound) {
NSString* parsedAirwayBill = [[[airWaybillSpan contents] substringFromIndex:(semicolon.location+1)] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
consigment.TrackingNumber = parsedAirwayBill;
}
}
NSString* sectionDate = @"";
//Parsing the tracking reply
BOOL nodeFound = NO;
for (HTMLNode *inputNode in rowNodes) {
int itemCounter = 0;
NSArray *cellNodes = [inputNode findChildTags:@"td"];
NSArray *cellDateNodes = [inputNode findChildTags:@"th"];
//Parse current section date
if ([cellDateNodes count]>0) {
NSString* tempSecDate = [[cellDateNodes objectAtIndex:0] contents];
if (tempSecDate != NULL) {
sectionDate = tempSecDate;
}
}
int counter = 0;
Record* trackingRecord = [[Record alloc] init];
//Extracting cells
for (HTMLNode *cellRealItem in cellNodes) {
if ([cellNodes count]> 2 ) {
nodeFound = YES;
switch (counter) {
case 1:
[trackingRecord setItemInfo:[self processCellText:[cellRealItem allContents]]];
break;
case 2:
[trackingRecord setPlace:[self processCellText:[cellRealItem allContents]]];
break;
case 3:
[trackingRecord setDate:[sectionDate stringByAppendingFormat:@", %@",[self processCellText:[cellRealItem allContents]]]];
break;
default:
break;
}
}
counter++;
}
//Processing location.
if (trackingRecord.Date != NULL) {
[trackingRecord setHasLocation:NO];
if (!trackingRecord.HasLocation) {
if (trackingRecord.Place != nil) {
NSRange comaRange = [trackingRecord.Place rangeOfString:@","];
if (comaRange.location != NSNotFound) {
NSString* trimmedLocation = [trackingRecord.Place substringFromIndex:comaRange.location + 1];
NSString* originalLocation = trackingRecord.Place;
trackingRecord.Place = trimmedLocation;
if (!trackingRecord.HasLocation) {
trackingRecord.Place = [originalLocation stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
}
}
}
}
//Add record (record is one step your package had taken on its way)
[consigment.TrackingRecords addObject:trackingRecord];
}
itemCounter++;
}
if (!nodeFound) {
return nil;
}
consigment.LastUpdate = [NSDate date];
//look through the tracking records and decide whether the package has been delivered
if([consigment.TrackingRecords count] > 0)
{
//Reverse the order of tracking steps
consigment.TrackingRecords = [[NSMutableArray alloc] initWithArray:[[consigment.TrackingRecords reverseObjectEnumerator] allObjects]];
Record* lastRecord = [consigment.TrackingRecords lastObject];
consigment.LastKnownStatus = lastRecord.ItemInfo;
consigment.IsTracked = YES;
NSRange deliveredENG = [consigment.LastKnownStatus rangeOfString:DeliveredFlag];
if (deliveredENG.location != NSNotFound) {
//set delivered flags
consigment.IsDelivered = YES;
}
}
//In case of more parser (e.g. FedEx, UPS) implemented this flag indicates the service selected
consigment.Service = serviceID;
return consigment;
}
//Cleaning the cell text in the tracking table
- (NSString*)processCellText:(NSString*)rawText
{
NSString *fullResult = @""; // Empty string just in case something went wrong while parsing the cell
if ([rawText length] > 0) {
@try {
NSString* result = [rawText stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString* firstLetterCapital = [[result substringToIndex:1] uppercaseString];
result = [result substringFromIndex:1];
fullResult = [[firstLetterCapital stringByAppendingString:result] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
@catch (NSException *exception) {
NSLog(@"Cell Text Parsing error\nText to parse:%@\nParsing error %@", rawText, exception.debugDescription);
}
}
return fullResult;
}
//Parsing the string for status message
- (NSString*)extractStatus:(NSString*)rawStatus
{
NSString* message = NSLocalizedString(@"N/A", @"N/A");
NSRange slashRange = [rawStatus rangeOfString:@"/"];
if (slashRange.location != NSNotFound) {
NSString* languageOne = [rawStatus substringToIndex:slashRange.location];
NSString* languageTwo = [rawStatus substringFromIndex:slashRange.location + 1];
NSString * language = [[NSLocale preferredLanguages] objectAtIndex:0];
if ([language isEqualToString:@"en"]) {
message = [languageTwo stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
else
{
message = [languageOne stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
}
else {
message = [rawStatus stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
return message;
}
//Main method of this tracking processor. Starts the async request to the DHL server.
//Use 2111111111 waybill number for tracking.
- (void)getParcelBy:(NSString*)TrackingNumber
{
NSString * language = [[NSLocale preferredLanguages] objectAtIndex:0];
responseData = [NSMutableData data];
//This is the official HTML based API link from the DHL.
NSString* trackingString = [kDHLbaseURL stringByAppendingFormat:@"&AWB=%@", TrackingNumber];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:trackingString] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30];
NSString *params = [[NSString alloc] init];
[request setHTTPMethod:@"GET"];
[request setHTTPShouldHandleCookies:YES];
[request setHTTPBody:[params dataUsingEncoding:NSUTF8StringEncoding]];
[request addValue:kMIMETypeURLEncodedForm forHTTPHeaderField:kContentType];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[responseData setLength:0];
}
//Add data as it arrives.
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[responseData appendData:data];
}
//Data has arrived. Let's start parsing.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(@"Response handling");
NSLog(@"PACKAGE size %i ", [responseData length]);
Parcel* package = [self getDetails:responseData];
NSLog(@"Package records count %i", [package.TrackingRecords count]);
NSLog(@"Last known status: %@", package.LastKnownStatus);
if (package.IsTracked) {
NSLog(@"DHL parcel %@", package.TrackingNumber);
self.completeBlock(YES, [NSString stringWithFormat:@"DHL parcel %@", package.TrackingNumber], package);
}
else {
//Callback so you can notify user if an exception occurs.
self.completeBlock(NO, NSLocalizedString(@"DHLNoSuchParcel", @"DHLNoParcel"), Nil);
}
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(@"Error %@", error.debugDescription);
self.completeBlock(NO, NSLocalizedString(@"DHLTimeout", @"Timeout"), Nil);
}
- (NSString*)parseLocation:(NSString *)place
{
//This is a hook method, you may want to implement here Google Maps parsing or
//any other kind of location related service.
return place;
}
@end