-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathXmlParser.m
284 lines (170 loc) · 7.58 KB
/
XmlParser.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
//
// XmlParser.m
// FeeFactor
//
// Created by Luke Du on 19/05/10.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//
#import "XmlParser.h"
#import "GDataXMLNode.h"
#import <Foundation/NSObjCRuntime.h>
#import "objc/runtime.h"
#import "TypeMapping.h"
#import "XmlHeaderHelper.h"
static const char* getPropertyType(objc_property_t property) {
// parse the property attribues. this is a comma delimited string. the type of the attribute starts with the
// character 'T' should really just use strsep for this, using a C99 variable sized array.
const char *attributes = property_getAttributes(property);
char buffer[1 + strlen(attributes)];
strcpy(buffer, attributes);
char *state = buffer;
char *attribute;
while ((attribute = strsep(&state, ",")) != NULL) {
if (attribute[0] == 'T' && strlen(attribute)>2) {
// return a pointer scoped to the autorelease pool. Under GC, this will be a separate block.
return (const char *)[[NSData dataWithBytes:(attribute + 3) length:strlen(attribute)-4] bytes];
}else if (attribute[0] == 'T' && strlen(attribute)==2) {
return (const char *)[[NSData dataWithBytes:(attribute + 1) length:strlen(attribute)] bytes];
}
}
return "@";
}
@implementation XmlParser
//Method to get property type and name of a given object
+ (NSMutableDictionary *)propertDictionary:(NSObject *) objt{
unsigned int outCount, i;
NSMutableDictionary * dic = [NSMutableDictionary dictionaryWithCapacity:1];
objc_property_t *properties = class_copyPropertyList([objt class], &outCount);
for(i = 0; i < outCount; i++) {
objc_property_t property = properties[i];
const char *propName = property_getName(property);
if(propName) {
const char *propType = getPropertyType(property);
NSString *propertyName = [NSString stringWithCString:propName encoding:NSUTF8StringEncoding];
NSString *propertyType = [NSString stringWithCString:propType encoding:NSUTF8StringEncoding];
[dic setValue:propertyType forKey:propertyName];
}
}
free(properties);
return dic;
}
//return value of a root element
//such as: <?xml version="1.0" encoding="UTF-8"?><postResult namespace="http://xxx.com">2</postResult>
//this method will return the postResult:2
+ (NSString *)getResult:(NSString *)xmlString{
NSString *xmlStr = xmlString;
NSError *error;
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithXMLString:xmlStr options:0 error:&error];
if (doc == nil) {
NSLog(@"doc doesn't exist");
return nil;
}
GDataXMLElement *anElement = [doc rootElement];
NSLog(@"stringValue :: %@", anElement.stringValue);
if (anElement) {
return anElement.stringValue;
}
else {
return @"";
}
}
//convert xml string into object the same type as given object.
-(id)fromXml:(NSString *)xmlString withObject:(id)obj{
NSString *xmlStr = xmlString;
//xmlStr = [xmlStr stringByReplacingOccurrencesOfString:@"xmlns" withString:@"noNSxml"];
xmlStr = [xmlStr stringByReplacingOccurrencesOfString:@"ns1:" withString:@""];
NSError *error;
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithXMLString:xmlStr options:0 error:&error];
if (doc == nil) {
NSLog(@"doc doesn't exist");
return nil;
}
NSLog(@"xmlString :: %@", xmlString);
NSMutableDictionary *propertyDic = [XmlParser propertDictionary:obj];
NSLog(@"propertyDic :: %@", propertyDic);
const char *objectName = class_getName([obj class]);
NSString *objectNameStr = [NSString stringWithCString:objectName encoding:NSASCIIStringEncoding];
NSLog(@"objectNameStr :: %@", objectNameStr);
GDataXMLElement *anElement = [doc rootElement];
NSLog(@"stringValue :: %@", anElement.name);
NSArray *objects;
if ([objectNameStr isEqualToString:[[doc rootElement] name]]) {
objects = [NSArray arrayWithObject:[doc rootElement]];
}
else {
objects = [doc nodesForXPath:[NSString stringWithFormat:@"//%@", objectNameStr] error:nil];
}
if (![objects count]) {
NSLog(@"no given object");
return nil;
}
NSObject * createdObject;
NSLog(@"objects :: %@", objects);
//NSMutableArray *returnArray = [NSMutableArray arrayWithCapacity:[objects count]];
NSMutableArray *returnArray = [[NSMutableArray alloc] init];
for (GDataXMLElement *thisObeject in objects) {
createdObject = [[[NSClassFromString(objectNameStr) alloc] init] autorelease];
NSLog(@"thisObeject is %@",thisObeject);
for (NSString *key in propertyDic) {
NSLog(@"key: %@, value: %@", key, [propertyDic objectForKey:key]);
NSArray *anArray = [thisObeject elementsForName:key];
NSLog(@"anArray :: %@", anArray);
if (anArray.count > 0) {
GDataXMLElement *anElement = (GDataXMLElement *) [anArray objectAtIndex:0];
NSLog(@"anElement :: %@",anElement.stringValue);
if ([[propertyDic objectForKey:key] isEqualToString:nsNumberType]) {
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber * aNumber = [f numberFromString:anElement.stringValue];
[f release];
[createdObject setValue:aNumber forKey:key];
}
else if([[propertyDic objectForKey:key] isEqualToString:booleanType]){
[createdObject setValue:[NSNumber numberWithInt:[anElement.stringValue boolValue]] forKey:key];
}
else {
[createdObject setValue:anElement.stringValue forKey:key];
}
}
}
[returnArray addObject:createdObject];
}
NSLog(@"return array has %d objects",[returnArray count]);
return returnArray;
}
//convert object to xml string, you could modify the type maping to fit your requirement,
//the reperesentation of type could be found in objective-c runtime reference.
-(NSString *)toXml:(id)object andTag:(NSString *)tag inNameSpace:(NSString *)nameSpace{
const char *objectName = class_getName([object class]);
NSString *objectNameStr = [[NSString alloc] initWithBytes:objectName length:strlen(objectName) encoding:NSASCIIStringEncoding];
GDataXMLElement * objectElement = [GDataXMLNode elementWithName:objectNameStr];
[objectElement addNamespace:[GDataXMLNode namespaceWithName:nil stringValue:nameSpace]];
NSMutableDictionary * propertyDic = [XmlParser propertDictionary:object];
NSString *nodeValue = [NSString stringWithFormat:@"%@",@""];
for (NSString *key in propertyDic) {
if ([object valueForKey:key]!=nil){
if ([[propertyDic objectForKey:key] isEqualToString:@"l"]) {
nodeValue = [NSString stringWithFormat:@"%llu",[[object valueForKey:key] unsignedLongLongValue]];
}else if ([[propertyDic objectForKey:key] isEqualToString:@"i"]) {
nodeValue = [NSString stringWithFormat:@"%d",[object valueForKey:key]];
}else {
nodeValue = [NSString stringWithFormat:@"%@",[object valueForKey:key]];
}
if (nodeValue.length != 0) {
GDataXMLElement * childElement = [GDataXMLNode elementWithName:key stringValue:nodeValue];
[objectElement addChild:childElement];
}
}
}
GDataXMLDocument *document = [[GDataXMLDocument alloc] initWithRootElement:objectElement];
NSData *xmlData = document.XMLData;
NSString *xmlString = [[NSString alloc] initWithData:xmlData encoding:NSUTF8StringEncoding];
NSString *bodyString = [xmlString substringFromIndex:21];
NSString *headerString = [XmlHeaderHelper generateXmlHeader:tag and:nameSpace];
xmlString = [NSString stringWithFormat:@"%@%@",headerString,bodyString];
NSLog(@"xml string is :: %@",xmlString);
[objectNameStr release];
[document release];
return xmlString;
}
@end