详解iOS开发之将XML转换成树

本文介绍了一种在iOS开发中将XML数据转换为树形结构的方法。通过自定义XMLParser和TreeNode类,实现了XML的高效解析及树形结构的数据操作。

iOS开发之将XML转换成是本文要介绍的内容,开发中由于服务端与客户端是两种不同的平台,而且服务端又是老系统,不具备很好的面向对象的性质,所以导致客户端与服务端只好通过一些制定好的xml进行通信。

iOS中对XML的解析不像donet这么方便。当然也存在一些很方便的开源类库去调用,但是有些开源的类库显得很笨重。本文章将封装一个简单操作XML转换成的类方便自己操作:首先通过NSXMLParser从服务端获取XML,它可以一边下载,一边解析,然后转换成形结构,最后我们可以从形结构中去取值。

使用NSXMLParser解析XML:

NSXMLParser中主要有三个委托方法来解析XML:

1、parser:didStartElement: 当解析器对象遇到xml的开始标记时,调用这个方法。

2、parser:didEndElement:当解析器对象遇到xml的结束标记时,调用这个方法。

3、parser:foundCharacters:当解析器找到开始标记和结束标记之间的字符时,调用这个方法。

了解了NSXMLParser机制。然后我们来封装解析XML的类:XMLParser。

#import <CoreFoundation/CoreFoundation.h>    
#import "TreeNode.h"
@interface XMLParser : NSObject
{
NSMutableArray *stack;
}
+ (XMLParser *) sharedInstance;
- (TreeNode *) parseXMLFromURL: (NSURL *) url;
- (TreeNode *) parseXMLFromData: (NSData*) data;
@end

shareInstance使用一个单例。

调用parseXMLFromURL方法,需要一个NSURL的参数,返回我们需要的树节点。

调用parseXMLFromData方法,需要一个NSData的参数,返回我们需要的树节点。

在此之前,先定义TreeNode类:

 1 #import <CoreFoundation/CoreFoundation.h>    
2 @interface TreeNode : NSObject
3 {
4 TreeNode *parent;
5 NSMutableArray *children;
6 NSString *key;
7 NSString *leafvalue;
8 }
9 @property (nonatomic, retain) TreeNode *parent;
10 @property (nonatomic, retain) NSMutableArray *children;
11 @property (nonatomic, retain) NSString *key;
12 @property (nonatomic, retain) NSString *leafvalue;
13 @property (nonatomic, readonly) BOOL isLeaf;
14 @property (nonatomic, readonly) BOOL hasLeafValue;
15 @property (nonatomic, readonly) NSArray *keys;
16 @property (nonatomic, readonly) NSArray *allKeys;
17 @property (nonatomic, readonly) NSArray *uniqKeys;
18 @property (nonatomic, readonly) NSArray *uniqAllKeys;
19 @property (nonatomic, readonly) NSArray *leaves;
20 @property (nonatomic, readonly) NSArray *allLeaves;
21 @property (nonatomic, readonly) NSString *dump;
22 + (TreeNode *) treeNode;
23 - (NSString *) dump;
24 - (void) teardown;
25 // Leaf Utils
26 - (BOOL) isLeaf;
27 - (BOOL) hasLeafValue;
28 - (NSArray *) leaves;
29 - (NSArray *) allLeaves;
30 // Key Utils
31 - (NSArray *) keys;
32 - (NSArray *) allKeys;
33 - (NSArray *) uniqKeys;
34 - (NSArray *) uniqAllKeys;
35 // Search Utils
36 - (TreeNode *) objectForKey: (NSString *) aKey;
37 - (NSString *) leafForKey: (NSString *) aKey;
38 - (NSMutableArray *) objectsForKey: (NSString *) aKey;
39 - (NSMutableArray *) leavesForKey: (NSString *) aKey;
40 - (TreeNode *) objectForKeys: (NSArray *) keys;
41 - (NSString *) leafForKeys: (NSArray *) keys;
42
43 // Convert Utils
44 - (NSMutableDictionary *) dictionaryForChildren;
45 @end


TreeNode 实现:

  1 #import "TreeNode.h"    
2 // String stripper utility macro
3 #define STRIP(X) [X stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]
4 @implementation TreeNode
5 @synthesize parent;
6 @synthesize children;
7 @synthesize key;
8 @synthesize leafvalue;
9 #pragma mark Create and Initialize TreeNodes
10 - (TreeNode *) init
11 {
12 if (self = [super init])
13 {
14 self.key = nil;
15 self.leafvalue = nil;
16 self.parent = nil;
17 self.children = nil;
18 }
19 return self;
20 }
21 + (TreeNode *) treeNode
22 {
23 return [[[self alloc] init] autorelease];
24 }
25 #pragma mark TreeNode type routines
26 - (BOOL) isLeaf
27 {
28 return (self.children.count == 0);
29 }
30 - (BOOL) hasLeafValue
31 {
32 return (self.leafvalue != nil);
33 }
34 #pragma mark TreeNode data recovery routines
35 // Return an array of child keys. No recursion
36 - (NSArray *) keys
37 {
38 NSMutableArray *results = [NSMutableArray array];
39 for (TreeNode *node in self.children) [results addObject:node.key];
40 return results;
41 }
42 // Return an array of child keys with depth-first recursion.
43 - (NSArray *) allKeys
44 {
45 NSMutableArray *results = [NSMutableArray array];
46 for (TreeNode *node in self.children)
47 {
48 [results addObject:node.key];
49 [results addObjectsFromArray:node.allKeys];
50 }
51 return results;
52 }
53 - (NSArray *) uniqArray: (NSArray *) anArray
54 {
55 NSMutableArray *array = [NSMutableArray array];
56 for (id object in [anArray sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)])
57 if (![[array lastObject] isEqualToString:object]) [array addObject:object];
58 return array;
59 }
60 // Return a sorted, uniq array of child keys. No recursion
61
62 - (NSArray *) uniqKeys
63 {
64 return [self uniqArray:[self keys]];
65 }
66 // Return a sorted, uniq array of child keys. With depth-first recursion
67
68 - (NSArray *) uniqAllKeys
69 {
70 return [self uniqArray:[self allKeys]];
71 }
72 // Return an array of child leaves. No recursion
73
74 - (NSArray *) leaves
75 {
76 NSMutableArray *results = [NSMutableArray array];
77 for (TreeNode *node in self.children) if (node.leafvalue) [results addObject:node.leafvalue];
78 return results;
79 }
80 // Return an array of child leaves with depth-first recursion.
81
82 - (NSArray *) allLeaves
83 {
84 NSMutableArray *results = [NSMutableArray array];
85 for (TreeNode *node in self.children)
86 {
87 if (node.leafvalue) [results addObject:node.leafvalue];
88 [results addObjectsFromArray:node.allLeaves];
89 }
90 return results;
91 }
92 #pragma mark TreeNode search and retrieve routines
93 // Return the first child that matches the key, searching recursively breadth first
94 - (TreeNode *) objectForKey: (NSString *) aKey
95 {
96 TreeNode *result = nil;
97 for (TreeNode *node in self.children)
98 if ([node.key isEqualToString: aKey])
99 {
100 result = node;
101 break;
102 }
103 if (result) return result;
104 for (TreeNode *node in self.children)
105 {
106 result = [node objectForKey:aKey];
107 if (result) break;
108 }
109 return result;
110 }
111 // Return the first leaf whose key is a match, searching recursively breadth first
112
113 - (NSString *) leafForKey: (NSString *) aKey
114 {
115 TreeNode *node = [self objectForKey:aKey];
116 return node.leafvalue;
117 }
118 // Return all children that match the key, including recursive depth first search.
119
120 - (NSMutableArray *) objectsForKey: (NSString *) aKey
121 {
122 NSMutableArray *result = [NSMutableArray array];
123 for (TreeNode *node in self.children)
124 {
125 if ([node.key isEqualToString: aKey]) [result addObject:node];
126 [result addObjectsFromArray:[node objectsForKey:aKey]];
127 }
128 return result;
129 }
130 // Return all leaves that match the key, including recursive depth first search.
131
132 - (NSMutableArray *) leavesForKey: (NSString *) aKey
133 {
134 NSMutableArray *result = [NSMutableArray array];
135 for (TreeNode *node in [self objectsForKey:aKey])
136 if (node.leafvalue)
137 [result addObject:node.leafvalue];
138 return result;
139 }
140 // Follow a key path that matches each first found branch, returning object
141
142 - (TreeNode *) objectForKeys: (NSArray *) keys
143
144 {
145 if ([keys count] == 0) return self;
146 NSMutableArray *nextArray = [NSMutableArray arrayWithArray:keys];
147 [nextArray removeObjectAtIndex:0];
148 for (TreeNode *node in self.children)
149 {
150 if ([node.key isEqualToString:[keys objectAtIndex:0]])
151 return [node objectForKeys:nextArray];
152 }
153 return nil;
154 }
155 // Follow a key path that matches each first found branch, returning leaf
156
157 - (NSString *) leafForKeys: (NSArray *) keys
158 {
159 TreeNode *node = [self objectForKeys:keys];
160 return node.leafvalue;
161 }
162 #pragma mark output utilities
163 // Print out the tree
164
165 - (void) dumpAtIndent: (int) indent into:(NSMutableString *) outstring
166 {
167 for (int i = 0; i < indent; i++) [outstring appendString:@"--"];
168 [outstring appendFormat:@"[%2d] Key: %@ ", indent, key];
169 if (self.leafvalue) [outstring appendFormat:@"(%@)", STRIP(self.leafvalue)];
170 [outstring appendString:@"\n"];
171 for (TreeNode *node in self.children) [node dumpAtIndent:indent + 1 into: outstring];
172 }
173 - (NSString *) dump
174 {
175 NSMutableString *outstring = [[NSMutableString alloc] init];
176 [self dumpAtIndent:0 into:outstring];
177 return [outstring autorelease];
178 }
179 #pragma mark conversion utilities
180 // When you're sure you're the parent of all leaves, transform to a dictionary
181
182 - (NSMutableDictionary *) dictionaryForChildren
183 {
184 NSMutableDictionary *results = [NSMutableDictionary dictionary];
185 for (TreeNode *node in self.children)
186 if (node.hasLeafValue) [results setObject:node.leafvalue forKey:node.key];
187 return results;
188 }
189 #pragma mark invocation forwarding
190 // Invocation Forwarding lets node act like array
191
192 - (id)forwardingTargetForSelector:(SEL)sel
193 {
194 if ([self.children respondsToSelector:sel]) return self.children;
195 eturn nil;
196 }
197 // Extend selector compliance
198 - (BOOL)respondsToSelector:(SEL)aSelector
199
200 {
201 if ( [super respondsToSelector:aSelector] ) return YES;
202 if ([self.children respondsToSelector:aSelector]) return YES;
203 return NO;
204 }
205 // Allow posing as NSArray class for children
206 - (BOOL)isKindOfClass:(Class)aClass
207
208 {
209 if (aClass == [TreeNode class]) return YES;
210 if ([super isKindOfClass:aClass]) return YES;
211 if ([self.children isKindOfClass:aClass]) return YES;
212 return NO;
213 }
214 #pragma mark cleanup
215
216 - (void) teardown
217 {
218 for (TreeNode *node in [[self.children copy] autorelease]) [node teardown];
219 [self.parent.children removeObject:self];
220 self.parent = nil;
221 }
222
223 - (void) dealloc
224 {
225 self.parent = nil;
226 self.children = nil;
227 self.key = nil;
228 self.leafvalue = nil;
229 [super dealloc];
230 }
231 @end

 

从上面的代码可以看出,定义了很多方便的方法来获取数据。

1、teardown:清除所有节点

2、isLeaf:判断是否是叶子节点

3、hasLeafValue:判断节点是否有值

4、- (NSArray *) leaves:返回节点的所有一级子节点值

5、- (NSArray *) allLeaves:返回节点的所有子节点的值

6、keys; 返回节点所有一级子节点名称。

7、 allKeys; 返回节点所有子节点名称。

8、 uniqKeys;返回节点一级子节点名称,不重复。

9、uniqAllKeys;返回节点子节点名称,不重复。

10、- (TreeNode *) objectForKey:根据节点名称查询节点

11、- (NSString *) leafForKey: (NSString *) aKey:根据节点名称查询出节点的值

12、- (NSMutableArray *) objectsForKey: (NSString *) aKey;根据节点名称查询出所以满足条件的节点

13、- (NSMutableArray *) leavesForKey: (NSString *) aKey;根据节点名称查询出所以满足条件的节点的值

14、- (TreeNode *) objectForKeys: (NSArray *) keys;:根据节点名称路径查询出第一个满足条件的节点。

15、- (NSString *) leafForKeys: (NSArray *) keys 根据节点名称路径查询出第一个满足条件的节点的值。

16、- (NSMutableDictionary *) dictionaryForChildren:将转换成dictionary定义好了,下面实现XMLParser类:

  1. #import "XMLParser.h"    
  2. @implementation XMLParser    
  3. static XMLParser *sharedInstance = nil;    
  4. // Use just one parser instance at any time    
  5. +(XMLParser *) sharedInstance     
  6. {    
  7.     if(!sharedInstance) {    
  8.         sharedInstance = [[self alloc] init];    
  9.     }    
  10.     return sharedInstance;    
  11. }    
  12. // Parser returns the tree root. You may have to go down one node to the real results    
  13. - (TreeNode *) parse: (NSXMLParser *) parser    
  14. {    
  15.    stack = [NSMutableArray array];    
  16.     TreeNode *root = [TreeNode treeNode];    
  17.     root.parent = nil;    
  18.     root.leafvalue = nil;    
  19.     root.children = [NSMutableArray array];    
  20.     [stack addObject:root];    
  21.     [parser setDelegate:self];    
  22.     [parser parse];    
  23.     [parser release];    
  24.     // pop down to real root    
  25.     TreeNode *realroot = [[root children] lastObject];    
  26.     root.children = nil;    
  27.     root.parent = nil;    
  28.     root.leafvalue = nil;    
  29.     root.key = nil;    
  30.     realroot.parent = nil;    
  31.     return realroot;    
  32. }    
  33.  
  34. - (TreeNode *)parseXMLFromURL: (NSURL *) url    
  35. {       
  36.     TreeNode *results;    
  37.     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];    
  38.     NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];    
  39.     results = [self parse:parser];    
  40.     [pool drain];    
  41.     return results;    
  42. }    
  43. - (TreeNode *)parseXMLFromData: (NSData *) data    
  44. {       
  45.     TreeNode *results;    
  46.     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];    
  47.     NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];    
  48.     results = [self parse:parser];    
  49.     [pool drain];    
  50.     return results;    
  51. }    
  52. // Descend to a new element    
  53.  
  54. - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)
  55. namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict    
  56. {    
  57.     if (qName) elementName = qName;    
  58.     TreeNode *leaf = [TreeNode treeNode];    
  59.     leaf.parent = [stack lastObject];    
  60.     [(NSMutableArray *)[[stack lastObject] children] addObject:leaf];    
  61.     leaf.key = [NSString stringWithString:elementName];    
  62.     leaf.leafvalue = nil;    
  63.     leaf.children = [NSMutableArray array];    
  64.     [stack addObject:leaf];    
  65. }    
  66. // Pop after finishing element    
  67.  
  68. - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName    
  69. {    
  70.     [stack removeLastObject];    
  71. }    
  72. // Reached a leaf    
  73.  
  74. - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string    
  75. {    
  76.     if (![[stack lastObject] leafvalue])    
  77.     {    
  78.         [[stack lastObject] setLeafvalue:[NSString stringWithString:string]];    
  79.         return;    
  80.     }    
  81.     [[stack lastObject] setLeafvalue:[NSString stringWithFormat:@"%@%@", [[stack lastObject] leafvalue], string]];    
  82. }    
  83. @end  

使用这两个类:

下面看下我们如何使用这个类:

在iis中放下面这个xml:

  1. <?xml version="1.0" encoding="UTF-8"?>    
  2. <Login>    
  3. <LoginResult>True</LoginResult>    
  4. <LoginInfo>恭喜你登录成功</LoginInfo>    
  5. <LastLogin>2011-05-09 12:20</LastLogin>    
  6. <Right>    
  7. <A>1</A>    
  8. <B>1</B>    
  9. <C>0</C>    
  10. </Right>   
  11. </Login>  

使用下面代码获取web服务器上的xml,并将xml转换成树:

NSURL * url = [[NSURL alloc] initWithString:@"http://10.5.23.117:4444/Login.xml"];    
TreeNode *node = [parser parseXMLFromURL:url];

 

获取xml中的登录结果:

view sourceprint?NSString * result =  [node leafForKey:@"LoginResult"];  

类似xpath去取值:

NSArray *path =[[NSArray alloc]initWithObjects:@"Right",@"A",nil];      
NSString * result = [node leafForKeys:path];

将xml显示在tableview上:

 1 @implementation TreeBrowserController    
2 @synthesize root;
3 // Each instance of this controller has a separate root, as
4 // descending through the tree produces new roots.
5
6 - (id) initWithRoot:(TreeNode *) newRoot
7 {
8 if (self = [super init])
9 {
10 self.root = newRoot;
11 NSString *s =[newRoot dump];
12 if (newRoot.key) self.title = newRoot.key;
13 }
14 return self;
15 }
16 - (id)initWithStyle:(UITableViewStyle)style
17 {
18 self = [super initWithStyle:style];
19 if (self) {
20 // Custom initialization
21 }
22 return self;
23 }

 

 1 // The number of rows equals the number of children for a node    
2
3 - (NSInteger)tableView:(UITableView *)tableView
4 numberOfRowsInSection:(NSInteger)section
5 {
6 return [self.root.children count];
7 }
8 // Color code the cells that can be navigated through
9
10 - (UITableViewCell *)tableView:(UITableView *)tableView
11 cellForRowAtIndexPath:(NSIndexPath *)indexPath
12 {
13 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"generic"];
14 if (!cell) cell = [[[UITableViewCell alloc]
15 initWithFrame:CGRectZero reuseIdentifier:@"generic"]
16 autorelease];
17 TreeNode *child = [[self.root children]
18 objectAtIndex:[indexPath row]];
19 // Set text
20 if (child.hasLeafValue)
21 cell.textLabel.text = [NSString stringWithFormat:@"%@:%@",
22 child.key, child.leafvalue];
23 else
24 cell.textLabel.text = child.key;
25 // Set color
26 if (child.isLeaf)
27 cell.textLabel.textColor = [UIColor darkGrayColor];
28 else
29 cell.textLabel.textColor = [UIColor blackColor];
30 return cell;
31 }
32 // On selection, either push a new controller or show the leaf value
33
34 - (void)tableView:(UITableView *)tableView
35 didSelectRowAtIndexPath:(NSIndexPath *)indexPath
36
37 {
38 TreeNode *child =
39 [self.root.children objectAtIndex:[indexPath row]];
40 if (child.isLeaf)
41 {
42 return;
43 }
44 TreeBrowserController *tbc = [[[TreeBrowserController alloc]
45 initWithRoot:child] autorelease];
46 [self.navigationController pushViewController:tbc animated:YES];
47 }
48 // These controllers are ephemeral and need dealloc
49
50 - (void) dealloc
51 {
52 self.root = nil;
53 [super dealloc];
54 }
55 @end



效果:

详解iOS开发之将XML转换成树 

详解iOS开发之将XML转换成树

总结:详解iOS开发之将XML转换成的内容介绍完了,本文通过封装两个类库,可以从web上很高效获取xml,将xml转换成形结构,可以很方便的对进行操作。

 

 

iOS开发本文章将封装一个简单操作XML转换成树的类方便自己操作:首先通过NSXMLParser从服务端获取XML,它可以一边下载,一边解析,然后转换成树形结构,最后我们可以从树形结构中去取值。

IOS开发之将XML转换成是介绍的内容;上文所述:很好将xml转换成,并进行操作,但是忽略了对xml节点上属性的操作,现在让我来修改代码,将属性添加进来。

1、在treenode中加一个类型为NSDictionary的attributeDict用于存放属性。代码如下:

NSDictionary * attributeDict; 

2、在中可以在parser:didStartElement:方法中取到属性列表,在其中添加添加下面代码。

leaf.attributeDict = [[NSDictionary alloc] initWithDictionary:attributeDict];  

3、修改样例xml

<?xml version="1.0" encoding="UTF-8"?>    
<Login>
<LoginResult id="1">True</LoginResult>
<LoginInfo>OK</LoginInfo>
<LastLogin>2011-05-09 12:20</LastLogin>
<Right>
<A>1</A>
<B>1</B>
<C>0</C>
</Right>
</Login>


4、取属性id的值。

TreeNode * resultTreeNode =  [node objectForKey:@"LoginResult"];    
NSString *result = [resultTreeNode.attributeDict objectForKey:@"id"];



### 将数组转换为二叉结构 在 Java 中实现将数组转换为二叉结构的过程涉及创建节点类以及构建的方法。下面提供了一种基于完全二叉特性的方法来完这一操作。 #### 创建 TreeNode 类 为了表示二叉中的每一个节点,定义 `TreeNode` 类如下: ```java class TreeNode { int val; TreeNode left; TreeNode right; public TreeNode(int x) { val = x; } } ``` #### 数组转二叉函数 接下来编写一个辅助函数用于从给定整数类型的输入数组建立对应的二叉查找(BST),这里假设该数组已经按照层次遍历顺序排列好,并且可以形一棵完整的二叉。 ```java public class ArrayToBST { private static TreeNode sortedArrayToBST(int[] nums) { if (nums == null || nums.length == 0) return null; return createMinimalBST(nums, 0, nums.length - 1); } private static TreeNode createMinimalBST(int[] arr, int start, int end){ if(end < start) return null; int mid = (start + end)/2; TreeNode n = new TreeNode(arr[mid]); n.left = createMinimalBST(arr,start,mid-1); n.right = createMinimalBST(arr,mid+1,end); return n; } // 测试代码片段 public static void main(String args[]) { int [] num={1,2,3,4,5,6,7}; TreeNode root=sortedArrayToBST(num); System.out.println("Root value:"+root.val); } } ``` 上述代码实现了通过递归方式构造平衡的二叉搜索[^1]。对于非排序或者不满足特定条件的数据集,则可能需要先对其进行预处理再执行此过程。 注意,在实际应用中,如果要确保生的是二叉搜素而不是普通的二叉,那么传入的数组应该已经是有序状态下的数据集合;如果不是的话则需提前做升序或降序排列处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值