0、理论基础:
NSXML是iOS SDK自带的,也是苹果默认解析框架,采用SAX模式解析。NSXML框架中的核心是NSXMLParser和它的委托协议NSXMLParserDelegate。主要的解析工作是在委托协议NSXMLParserDelegate的实现类中完成的,委托中定义了很多回掉方法,在SAX解析器从上到下遍历XML文档的过程中,遇到开始标签、结束标签、文档开始、文档结束和字符串就会触发这些方法。这些方法有很多,比如下面的:
1、parserDidStartDocument,在文档开始的时候触发;
2、parser:didStartElement:namespaceURI:qualifiedName:attributes,遇到一个开始标签时触发,其中namespaceURI部分是命名空间,qualifiedName是限定名,attributes是字典类型的属性集合;
3、parser:foundCharacters,遇到字符串时触发;
4、parser:didEndElement:namespaceURI:qualifiedName,遇到结束标签时触发;
5、parserDidEndDocument,遇到文档结束时触发。
1、一个例子,从xml读取数据并显示到tableview上:
先来看我们的测试xml文件内容(这个是远程的,本地的需要再创建项目的时候,再拷贝一份):
首先我们创建一个测试工程ParserXML,把自带的storyboard、ViewController删掉,创建MainViewController(集成自UITableViewController),创建对应的group,这是处理处理过后的工程内容:
下面对其进行修改,在AppDelegate.m的(主要是初始化Main视图)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor grayColor];
[self.window makeKeyAndVisible];
MainViewController *mainController = [[MainViewController alloc] init];
self.window.rootViewController = mainController;
return YES;
}
并且在工程中删掉下边的这个(其实无所谓,删不删除都不会导致错误):
因为需要在tableView中显示数据,因此我们给tableView中加入一个动态数组:
在对应的viewDid中对其进行初始化(包括对dataArray和对表格的):
并且设置一个tableview的行数
好,下面补上从xml中读取数据的内容
新建一个XmlDataParser的一个类,他继承自NSobject,并且实现协议NSXMLParserDelegate
commond+NSXMLParserDelegate找到NSXMLParserDelegate.h的内容,取出最上边理论时候讲到的四个方法:
实现这四个方法的,达到解析xml的目的
因为,上一个类tableView中需要的数据源是NSMutableArray的,所以这里我们也新建一个NSMutableArray的dataArray对象,保存读取到的数据,当然我们需要一个NSMutableDictionary保存我们读取每一个xml子项的内容,还需要一个从xml读取出字符串的NSMutableString:
按照一开始理论的,我们在parserDidStartDocument中对成员变量进行初始化:
因为,我们不打算把数据清空,所以在parserDidEndDocument中,我们什么都不做,如果你打算清空数据,那么在这里完成是最好的时机(这里对两个临时变量清空,其实也没太大必要)
我们先来填foundCharacters,他是发现字符串的时候触发,所以这里:
按照逻辑,在一开始碰到xml的开始标签的时候,比如遇到Note,这是每一子项的开始标签,我们需要清空一下NSMutableDictionary以便我们存放一个子项;在比如遇到CDate的时候,只需要清空一个临时字符串就行了(因为他只是子项的一个数据项,所以这是我们的didStartElement):
可以看到这里有一个参数是attributeDict的,他的含义是,当你的每一个xml标签有属性值的时候,比如这里的<Note id = "1">,那么你可以继续进行匹配,进而取出后面的id的值
didEndElement是把对应的内容,填进Array中,这里也和上面是一样,同样要区别开每一个子项和数据项的操作
因为,我们是对xml的操作进行封装的,所以对外需要有一个接口;上面一开始我们提到,xml文件可能是本地的数据,也可能是web的数据,所以我们还得需要一个bool的标记:
下面我们来实现它,这个很简单,判断一个是本地读取文件,还是从web中获得数据:
看看这里的代码,因为从文件中读取,我们只需要在xml文件名前面跟上路径信息就行(用NSBundle mainBundle就很容易办到)
网络路径的文件,那么我们就需要先从NSData中取到数据,再去解析了
最后部分我们要对tableView的每一项进行设置,这个就不说了,查看代码:
这里提一下,也是我第一次创建cell的时候抛出未初始化错误的问题
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
// 填充对应的数据,从NSMutableArray中取出
}
因为自带的两行代码中,cell是没有alloc的,所以我们必须要在判断cell等于nil的时候,用alloc对其初始化;而且原有的一行代码是通过forIndexPath来加载的,所以我们去掉后面的forIndexPath只要前面的:
最后,我们来补上一开始获取xml内容的部分(分别对网络和本地的xml文件做测试):
2、演示效果: