关联:iOS中XML解析 (一) TBXML (实例:打印xml内容及存储到数组)

关于libxml库的基本使用,在http://xmlsoft.org/网上有文档。

准备工作:

  1. project=>Edit project setting =>Build=> Searche Paths=>Header Search Paths:把这个拷贝进去${SDKROOT}/usr/include/libxml2,网上有很多都是没给这个的${SDKROOT}。
  2. linking => other linker flags =>-lxml2拷贝进去
  3. 把dylib包添加导项目中去。
  4. 编译 如果还有问题,nclean all targets 确保 两项都打钩 并且 empty xcode 的cache

一、使用libxml读XML文件

要读xml,需要使用reader,这里介绍两种方式,一种从文件读取,一种从内存读取。其它就是通过libxml库中提供的两个API来建立reader.请看代码:

1、从文件建立reader

xmlTextReaderPtr  reader = xmlNewTextReaderFilename(xmlfile);

2、从内存建立reader

// char* memory, int size
xmlTextReaderPtr reader = xmlReaderForMemory(memory, size, NULL, "UTF-8", 0);

从上述代码来看,建立一个reader是非常容易的。

3、从reader中读数据

建立了reader之后,我们就可以通过reader的辅助函数来实现xml数据的读取。在这里,我讲述的是如何读一个文本方式的XML,并没有使用XML的专有模型。这种方式最原始,也是最容易理解的。

要读一个reader中的数据,使用xmlTextReaderRead来读一个元素,XML中的每一个元素都会经过reader依次读取,我们可以根据需要来检查当前reader位置的元素类型,并取出数据为已所用,当然还要释放由reader分配的数据空间。下面来看一下读的例子:

ret = xmlTextReaderRead(reader);
if (ret == 0) return 0;
if (ret != 1) return -2;
element = xmlTextReaderName(reader);  if (element != NULL)
{  ntype = xmlTextReaderNodeType(reader);  if (strcmp((const char*) element, "param-name") == 0)  {  xmlFree(element);  if (XML_READER_TYPE_ELEMENT == ntype)  {  /*......*/  }  }
}  

xmlTextReaderRead需要一个参数,就是我们前面进行的一个文本读取器指针,该函数返回1表示成功读取,0表示到达文件尾。当成功读取时,可能使用xmlTextReaderName读取当前位置的元素数据,并可以通过xmlTextTextReaderNodeType来读取XML元素的类型。

/** * xmlReaderTypes: * * Predefined constants for the different types of nodes. */
typedef enum {  XML_READER_TYPE_NONE = 0,  XML_READER_TYPE_ELEMENT = 1,  XML_READER_TYPE_ATTRIBUTE = 2,  XML_READER_TYPE_TEXT = 3,  XML_READER_TYPE_CDATA = 4,  XML_READER_TYPE_ENTITY_REFERENCE = 5,  XML_READER_TYPE_ENTITY = 6,  XML_READER_TYPE_PROCESSING_INSTRUCTION = 7,  XML_READER_TYPE_COMMENT = 8,  XML_READER_TYPE_DOCUMENT = 9,  XML_READER_TYPE_DOCUMENT_TYPE = 10,  XML_READER_TYPE_DOCUMENT_FRAGMENT = 11,  XML_READER_TYPE_NOTATION = 12,  XML_READER_TYPE_WHITESPACE = 13,  XML_READER_TYPE_SIGNIFICANT_WHITESPACE = 14,  XML_READER_TYPE_END_ELEMENT = 15,  XML_READER_TYPE_END_ENTITY = 16,  XML_READER_TYPE_XML_DECLARATION = 17
} xmlReaderTypes;  

reader支持如上类型,我们可以根据当前类型来读取数据,因为不现的类型,读取数据的方式不同,比如xmlTextReaderReadString只能读元素(XML_READER_TYPE_ELEMENT)的名称或者文件类型(XML_READER_TYPE_TEXT)的数据。注意一点就是reader是按顺序读取每一个元素,在写代码时,应该不要假定后面一定是什么元素或者特定类型,应该去检测,保证软件的稳定性。

使用xmlTextReaderReadString返回一个元素(xmlChar*类型)时,该区域是由库分配的内存区域,需要使用xmlFree来释放,不然就有内存泄漏。

4、读xml的reader的释放与清理

xmlTextReaderClose(reader);
xmlFreeTextReader(reader);
xmlDictCleanup();
xmlCleanupParser();
xmlMemoryDump();
xmlCleanupCharEncodingHandlers();  

有一个xmlTextReaderClose函数,当使用该函数时,要注意顺序,一定要在xmlFreeTextReader之前,不然就会出现错误。

二、实例

1. 假设xml地址为 http://cdn.domain.com/ipad/settings/config.xml 格式为:

<?xml version="1.0"?>
<settings>
<popupAd><show>1</show><count>3</count>
</popupAd>
</settings>

读取:

.h

#import <Foundation/Foundation.h>
#include <libxml/xmlreader.h>@interface NewsFeedParser : NSObject {}@end

.m

-(void)readXml
{NSURLResponse  *response;NSError        *error;NSURLRequest   *request     = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://cdn.domain.com/ipad/settings/config.xml"]];NSData         *settingData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];xmlTextReaderPtr reader = xmlReaderForMemory([settingData bytes], [settingData length], nil, nil, (XML_PARSE_NOENT|XML_PARSE_NOBLANKS | XML_PARSE_NOCDATA | XML_PARSE_NOERROR | XML_PARSE_NOWARNING));if(!reader) NSLog(@"Failed to load setting config xml !");else{char *temp;NSString *currentTagName = nil;NSString *currentTagValue = nil;NSMutableDictionary *config = [NSMutableDictionary dictionary];while (TRUE) {if(!xmlTextReaderRead(reader)) break;//NSLog(@"========> %s",xmlTextReaderName(reader));if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT){temp = (char *)xmlTextReaderConstName(reader);currentTagName = [NSString stringWithCString:temp encoding:NSUTF8StringEncoding];if([currentTagName isEqualToString:@"show"] || [currentTagName isEqualToString:@"count"]){temp = (char *)xmlTextReaderReadString(reader);currentTagValue = [NSString stringWithCString:temp encoding:NSUTF8StringEncoding];//NSLog(@"===> TagName: %@",currentTagName);//NSLog(@"===> TagValue: %@",currentTagValue);[config setObject:currentTagValue forKey:currentTagName];currentTagValue = nil;}}}NSLog(@"======> %@",[config objectForKey:@"show"]);NSLog(@"======> %@",[config objectForKey:@"count"]);}
}

2. 假设xml地址为 http://www.domain.com/feed/ipad/marketchart/main.rss 格式为:

<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
<channel>
<atom:link href="http://www.domain.com/feed/ipad/marketchart/main.rss" rel="self" type="application/rss+xml" />
<title><![CDATA[domain.com : Market data]]></title>
<description><![CDATA[Market data RSS Feed ]]></description>
<link>http://www.domain.com/feed/ipad/marketchart/main.rss</link>
<copyright>All articles are copyrighted by IBTimes.com</copyright><image><url>http://img.domain.com/www/site/2010/main/images/heading_editores_pick_logo.png</url><title><![CDATA[domain.com : Market data]]></title><link>http://www.domain.com/feed/ipad/marketchart/main.rss</link></image><item><title><![CDATA[DOW]]></title> <last>13085.53</last> <symbol>^DJI</symbol> <change>-114.02</change> <description><![CDATA[ description ]]></description> <pubDate>Wed, 04 Apr 2012 14:51:00 EDT</pubDate></item><item><title><![CDATA[NYSE]]></title> <last>8151.97</last> <symbol>$NYA</symbol> <change>0</change> <description><![CDATA[ description ]]></description> <pubDate>Fri, 24 Feb 2012 17:05:00 EST</pubDate></item><item><title><![CDATA[NASDAQ]]></title> <last>3063.63</last> <symbol>$COMP</symbol> <change>-49.94</change> <description><![CDATA[ description ]]></description> <pubDate>Wed, 04 Apr 2012 14:45:00 EDT</pubDate></item><item><title><![CDATA[S&P 500]]></title> <last>1399.64</last> <symbol>$SPX</symbol> <change>-13.74</change> <description><![CDATA[ description ]]></description> <pubDate>Wed, 04 Apr 2012 14:45:00 EDT</pubDate></item>
</channel>
</rss>

以item为单位的循环

NewsFeedParser.h

#import <Foundation/Foundation.h>
#include <libxml/xmlreader.h>@interface NewsFeedParser : NSObject {}+(NSMutableArray*) parseFeedFromUrl:(NSString *) url;@end

NewsFeedParser.m

#import "NewsFeedParser.h"@implementation NewsFeedParser+(NSMutableArray*) parseFeedFromUrl:(NSString *) url
{NSMutableArray *itemsArray = [NSMutableArray array];//NSLog(@"NewsFeedParser:%@ begin\n", url);NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];NSURLResponse *response;NSError *error;NSData *xmlData = [NSURLConnection sendSynchronousRequest:request returningResponse:&responseerror:&error];xmlTextReaderPtr reader = xmlReaderForMemory([xmlData bytes], [xmlData length], nil, nil, (XML_PARSE_NOENT|XML_PARSE_NOBLANKS | XML_PARSE_NOCDATA | XML_PARSE_NOERROR | XML_PARSE_NOWARNING));if (!reader) {NSLog(@"Failed to load xmlreader");return itemsArray;}NSString *currentTagName = nil;NSDictionary *currentItem = nil;NSString *currentTagValue = nil;bool itemStarted = false;bool authorStarted = false;bool categoryStarted = false;char* temp;while (true) {if (!xmlTextReaderRead(reader)) break;int type = xmlTextReaderNodeType(reader);switch (type) {case XML_READER_TYPE_END_ELEMENT:temp =  (char*)xmlTextReaderConstName(reader);currentTagName = [NSString stringWithCString:temp encoding:NSUTF8StringEncoding];if ([currentTagName isEqualToString:@"item"]) {itemStarted = false;} continue;case XML_READER_TYPE_ELEMENT://We are starting an elementtemp =  (char*)xmlTextReaderConstName(reader);currentTagName = [NSString stringWithCString:temp encoding:NSUTF8StringEncoding];if ([currentTagName isEqualToString:@"item"]) {//NSLog(@"Item begin\n");currentItem = [NSMutableDictionary dictionary];[itemsArray addObject:currentItem];itemStarted = true;authorStarted = false;categoryStarted = false;}if([currentTagName isEqualToString:@"author"]){authorStarted = true;categoryStarted = false;}if([currentTagName isEqualToString:@"category"]){categoryStarted = true;authorStarted = false;}if(itemStarted == true && [currentTagName isEqualToString:@"media:content"]){temp = (char*)xmlTextReaderGetAttribute(reader,"url");currentTagValue = [NSString stringWithCString:temp encoding:NSUTF8StringEncoding];[currentItem setValue:currentTagValue forKey:currentTagName];//NSLog(@"%@ - %@\n", currentTagName, currentTagValue);currentTagValue = nil;}continue;case XML_READER_TYPE_TEXT://The current tag has a text value, stick it into the current personif(itemStarted == false)continue;temp = (char*)xmlTextReaderConstValue(reader);currentTagValue = [NSString stringWithCString:temp encoding:NSUTF8StringEncoding];//NSLog(@"%@ - %@\n", currentTagName, currentTagValue);if([currentTagName isEqualToString:@"name"]){if(authorStarted)[currentItem setValue:currentTagValue forKey:@"author"];if(categoryStarted)[currentItem setValue:currentTagValue forKey:@"category"];}else{[currentItem setValue:currentTagValue forKey:currentTagName];}currentTagValue = nil;currentTagName = nil;continue;case XML_READER_TYPE_ATTRIBUTE://temp = (char*)xmlTextReaderConstValue(reader);//NSLog(@"%s\n", temp);default: continue;}}//NSLog(@"NewsFeedParser:%@ done\n", url);return itemsArray;}@end

ViewController.m

#import "NewsFeedParser.h"-(void) loadMarketData{dispatch_async(dispatch_get_global_queue(0, 0), ^{NSMutableArray *items = [NewsFeedParser parseFeedFromUrl:@"http://www.domain.com/feed/ipad/marketchart/main.rss"];if([items count] == 0)return;NSLog(@"Title => %@", [[items objectAtIndex:0] objectForKey:@"title"]);NSLog(@"Last=> %@", [[items objectAtIndex:0] objectForKey:@"last"]);NSLog(@"Change=> %@", [[items objectAtIndex:0] objectForKey:@"change"]);});
}

其他一些方法:

libxml库提供了一些.net风格的函数,以流的形式来读取并分析xml文件.

<libxml/xmlreader.h>xmlTextReader xmlTextReaderPtr //XmlReader的结构体及其指针xmlTextReaderPtr xmlReaderForFile (const char * filename, const char * encoding, int options) //打开一个xml文件并返回xmlreader对象,准备开始分析.int xmlTextReaderRead (xmlTextReaderPtr reader) //读取下一个节点(注意,是下一个,不是下一个同层节点)int xmlTextReaderNext (xmlTextReaderPtr reader) //读取下一个同层节点int xmlTextReaderNodeType (xmlTextReaderPtr reader) //判断当前节点的类型xmlChar *xmlTextReaderGetAttribute (xmlTextReaderPtr reader, const xmlChar * name) //获取当前节点的指定属性xmlChar *xmlTextReaderReadString (xmlTextReaderPtr reader) //读取当前节点下的textxmlNodePtr xmlTextReaderExpand (xmlTextReaderPtr reader) //将当前节点展开成一个节点对象(慎用)int xmlTextReaderHasValue (xmlTextReaderPtr reader) //判断当前节点是否有text值int xmlTextReaderHasAttributes (xmlTextReaderPtr reader) //判断当前节点是否包含属性int xmlTextReaderMoveToAttribute (xmlTextReaderPtr reader, const xmlChar * name) //移动指针到当前节点的指定属性名的属性int xmlTextReaderMoveToAttributeNo (xmlTextReaderPtr reader, int no) //移动指针到当前节点指定属性编号的属性int xmlTextReaderMoveToElement (xmlTextReaderPtr reader) //将指针移会当前节点int xmlTextReaderMoveToFirstAttribute (xmlTextReaderPtr reader) //将指针移动到当前节点的第一个属性int xmlTextReaderMoveToNextAttribute (xmlTextReaderPtr reader) //将指针移动到当前节点的下一个属性xmlChar *xmlTextReaderName (xmlTextReaderPtr reader) //返回当前节点的名字

libxml自定义了一个字符类型xmlChar,其本质是 unsigned char.

另外,libxml提供了一个宏来将char*转换成xmlChar*, 名字很有趣,叫 BAD_CAST 它的本质其实是 unsigned char*.

为了方便对xmlChar类型字符串的操作,libxml提供了自己的函数,它们的定义于标准c函数库中的字符串函数很像.

xmlChar* xmlStrcat (xmlChar *cur, const xmlChar * add)const xmlChar *xmlStrchr(const xmlChar * str, xmlChar val)int xmlStrcmp (const xmlChar * str1, const xmlChar * str2)int xmlStrlen (const xmlChar * str)xmlChar *xmlStrncat (xmlChar * cur, const xmlChar * add, int len)int xmlStrncmp (const xmlChar * str1, const xmlChar * str2, int len)const xmlChar *xmlStrstr (const xmlChar * str, const xmlChar * val)

更多函数大家可以参考

http://xmlsoft.org/html/libxml-xmlstring.html

关联:iOS中XML解析 (一) TBXML (实例:打印xml内容及存储到数组)

iOS中XML解析 (二) libxml2(实例:打印xml内容及存储到数组)相关推荐

  1. iOS中XML解析 (一) TBXML (实例:打印xml内容及存储到数组)

    关联:iOS中XML解析 (二) libxml2(实例:打印xml内容及存储到数组) 在时间上TBXML占优,libxml2支持了边下载边解析. 来源:http://www.codeios.com/f ...

  2. 用“XML解析开发包Jaxp”对XML文件进行Dom方式的CRUD操作

    IT程序员开发必备-各类资源下载清单,史上最全IT资源,个人收藏总结! package edu.jaxp; import java.io.FileNotFoundException; import j ...

  3. java自带的xml解析_Java自带的XML解析

    JAXP(Java API for XML Processing,意为处理XML的Java API) 解析XML一般有两种方式: 一种是DOM方式:一次性读取XML内容存入内存 优点:能进行各种增删改 ...

  4. IOS中Json解析的四种方法

    2019独角兽企业重金招聘Python工程师标准>>> 作为一种轻量级的数据交换格式,json正在逐步取代xml,成为网络数据的通用格式. 有的json代码格式比较混乱,可以使用此& ...

  5. 【转】IOS中Json解析的四种方法

    原文网址:http://blog.csdn.net/enuola/article/details/7903632 作为一种轻量级的数据交换格式,json正在逐步取代xml,成为网络数据的通用格式. 有 ...

  6. ios json包含html,IOS中Json解析的四种方法

    发现自己有很多文档,所以现在整理一下,以防忘了... 作为一种轻量级的数据交换格式,json正在逐步取代xml,成为网络数据的通用格式. 有的json代码格式比较混乱,可以使用此"http: ...

  7. Python解析xml文件,此实例将xml设置为模版(from lxml import etree)

    xml文件(template.xml) <core><template><!-- General information about the template --> ...

  8. iOS中XML解析汇总

    在时间上TBXML占优,libxml2支持了边下载边解析. 来源:http://www.codeios.com/forum.php?mod=viewthread&tid=9880&hi ...

  9. iOS中的XML解析

    解析方式分类: 解析 XML 通常有两种方式,DOM 和 SAX:DOM解析XML时,读入整个XML文档并构建一个驻留内存的树结构(节点树),通过遍历树结构可以检索任意XML节点,读取它的属性和值. ...

最新文章

  1. YESLAB的数据中心课程介绍
  2. JAVA中类的访问修饰符的作用范围
  3. 【实践】js实现随机不重复抽取数组中元素
  4. Runtime使用单例模式,饿汉式
  5. 银行业务队列简单模拟(队列queue)
  6. MATLAB中的清除,oop – 在MATLAB中清除类定义
  7. Linux上快速安装软RAID详细步骤
  8. Java中的try/catch/finally
  9. mysql 自动备份脚本+自动上传
  10. mysql 自定义函数教程_Mysql 自定义函数
  11. jsp mysql 乱码_jsp插入mysql数据库后乱码的解决办法
  12. 凌阳单片机c语言延时函数,凌阳单片机C语言(网站整理).doc
  13. 百度网盘资源搜索网站大全
  14. 青蓝电影质感LR预设达芬奇/PS/PR/LUT人像lightroom胶片调色滤镜插件
  15. Python3 L13
  16. uniapp uni-swipe-action 滑动删除
  17. 锐意创新,引领音视频未来
  18. 云计算工程师面试题集锦,云计算面试题及答案
  19. fastadmin 文本框修改为图片或文件上传
  20. 北航研究生计算机网络实验报告,实验4-北航研究生计算机网络实验.doc

热门文章

  1. 判断数正负(信息学奥赛一本通-T1039)
  2. 计算机等级考试机试试题,计算机等级考试二级VFP机试试题18
  3. 96KB存储器的怎么算地址范围_产品条码怎么申请费用
  4. Vision Transformer中的自监督学习
  5. [结构力学] 铰结三角形规律中虚铰也记为单铰
  6. php报错致命错误203,Centos7 下安装PHP7 phpredis扩展报错解决办法 致命错误:ext/standard/php_smart_str.h...
  7. vue设置isactive_vue 绑定样式的几种方式
  8. java 设备集成,java 集成 海康 SDK
  9. 超级SEO静态页面生成系统源码
  10. 共享按摩椅理财系统|金融投资理财系统