现在的位置: 首页 > 综合 > 正文

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

2018年01月08日 ⁄ 综合 ⁄ 共 15257字 ⁄ 字号 评论关闭

关于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

C代码  收藏代码
  1. xmlTextReaderPtr  reader = xmlNewTextReaderFilename(xmlfile);  

 

2、从内存建立reader

C代码  收藏代码
  1. // char* memory, int size    
  2. xmlTextReaderPtr reader = xmlReaderForMemory(memory, size, NULL, "UTF-8", 0);  

 

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

 

3、从reader中读数据

 

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

 

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

C代码  收藏代码
  1. ret = xmlTextReaderRead(reader);    
  2. if (ret == 0) return 0;    
  3. if (ret != 1) return -2;    
  4. element = xmlTextReaderName(reader);    
  5.     
  6. if (element != NULL)    
  7. {    
  8.     ntype = xmlTextReaderNodeType(reader);    
  9.     if (strcmp((const char*) element, "param-name") == 0)    
  10.     {    
  11.         xmlFree(element);    
  12.         if (XML_READER_TYPE_ELEMENT == ntype)    
  13.         {    
  14.         /*......*/    
  15.         }    
  16.     }    
  17. }    

 

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

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

 

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

 

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

 

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

C代码  收藏代码
  1. xmlTextReaderClose(reader);    
  2. xmlFreeTextReader(reader);    
  3. xmlDictCleanup();    
  4. xmlCleanupParser();    
  5. xmlMemoryDump();    
  6. xmlCleanupCharEncodingHandlers();    

 

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

 

二、实例

 

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

Xml代码  收藏代码
  1. <?xml version="1.0"?>  
  2. <settings>  
  3. <popupAd>  
  4.     <show>1</show>  
  5.     <count>3</count>  
  6. </popupAd>  
  7. </settings>  

 

读取:

.h

C代码  收藏代码
  1. #import <Foundation/Foundation.h>  
  2. #include <libxml/xmlreader.h>  
  3.   
  4. @interface NewsFeedParser : NSObject {  
  5.       
  6. }  
  7.   
  8. @end  

 

.m

Java代码  收藏代码
  1. -(void)readXml  
  2. {  
  3.     NSURLResponse  *response;  
  4.     NSError        *error;  
  5.     NSURLRequest   *request     = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://cdn.domain.com/ipad/settings/config.xml"]];  
  6.     NSData         *settingData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];  
  7.       
  8.     xmlTextReaderPtr reader = xmlReaderForMemory([settingData bytes], [settingData length], nil, nil, (XML_PARSE_NOENT|XML_PARSE_NOBLANKS | XML_PARSE_NOCDATA | XML_PARSE_NOERROR | XML_PARSE_NOWARNING));  
  9.       
  10.     if(!reader) NSLog(@"Failed to load setting config xml !");  
  11.     else  
  12.     {  
  13.         char *temp;  
  14.         NSString *currentTagName = nil;  
  15.         NSString *currentTagValue = nil;  
  16.         NSMutableDictionary *config = [NSMutableDictionary dictionary];  
  17.           
  18.         while (TRUE)   
  19.         {  
  20.             if(!xmlTextReaderRead(reader)) break;  
  21.               
  22.             //NSLog(@"========> %s",xmlTextReaderName(reader));  
  23.               
  24.             if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT)  
  25.             {  
  26.                 temp = (char *)xmlTextReaderConstName(reader);  
  27.                 currentTagName = [NSString stringWithCString:temp encoding:NSUTF8StringEncoding];  
  28.                   
  29.                 if([currentTagName isEqualToString:@"show"] || [currentTagName isEqualToString:@"count"])  
  30.                 {  
  31.                     temp = (char *)xmlTextReaderReadString(reader);  
  32.                     currentTagValue = [NSString stringWithCString:temp encoding:NSUTF8StringEncoding];  
  33.                       
  34.                     //NSLog(@"===> TagName: %@",currentTagName);  
  35.                     //NSLog(@"===> TagValue: %@",currentTagValue);  
  36.                       
  37.                     [config setObject:currentTagValue forKey:currentTagName];  
  38.                     currentTagValue = nil;  
  39.                 }  
  40.             }  
  41.         }  
  42.           
  43.         NSLog(@"======> %@",[config objectForKey:@"show"]);  
  44.         NSLog(@"======> %@",[config objectForKey:@"count"]);  
  45.     }  
  46. }  

 

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

Xml代码  收藏代码
  1. <?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/">  
  2. <channel>  
  3. <atom:link href="http://www.domain.com/feed/ipad/marketchart/main.rss" rel="self" type="application/rss+xml" />  
  4. <title><![CDATA[domain.com : Market data]]></title>  
  5. <description><![CDATA[Market data RSS Feed ]]></description>  
  6. <link>http://www.domain.com/feed/ipad/marketchart/main.rss</link>  
  7. <copyright>All articles are copyrighted by IBTimes.com</copyright>  
  8.  <image>  
  9.     <url>http://img.domain.com/www/site/2010/main/images/heading_editores_pick_logo.png</url>  
  10.     <title><![CDATA[domain.com : Market data]]></title>  
  11.     <link>http://www.domain.com/feed/ipad/marketchart/main.rss</link>  
  12.  </image>  
  13.   <item>  
  14.   <title><![CDATA[DOW]]></title>   
  15.   <last>13085.53</last>   
  16.   <symbol>^DJI</symbol>   
  17.   <change>-114.02</change>   
  18.   <description><![CDATA[ description ]]></description>   
  19.   <pubDate>Wed, 04 Apr 2012 14:51:00 EDT</pubDate>  
  20.   </item>  
  21.   <item>  
  22.   <title><![CDATA[NYSE]]></title>   
  23.   <last>8151.97</last>   
  24.   <symbol>$NYA</symbol>   
  25.   <change>0</change>   
  26.   <description><![CDATA[ description ]]></description>   
  27.   <pubDate>Fri, 24 Feb 2012 17:05:00 EST</pubDate>  
  28.   </item>  
  29.   <item>  
  30.   <title><![CDATA[NASDAQ]]></title>   
  31.   <last>3063.63</last>   
  32.   <symbol>$COMP</symbol>   
  33.   <change>-49.94</change>   
  34.   <description><![CDATA[ description ]]></description>   
  35.   <pubDate>Wed, 04 Apr 2012 14:45:00 EDT</pubDate>  
  36.   </item>  
  37.   <item>  
  38.   <title><![CDATA[S&P 500]]></title>   
  39.   <last>1399.64</last>   
  40.   <symbol>$SPX</symbol>   
  41.   <change>-13.74</change>   
  42.   <description><![CDATA[ description ]]></description>   
  43.   <pubDate>Wed, 04 Apr 2012 14:45:00 EDT</pubDate>  
  44.   </item>  
  45. </channel>  
  46. </rss>  

 

以item为单位的循环

 

NewsFeedParser.h

C代码  收藏代码
  1. #import <Foundation/Foundation.h>  
  2. #include <libxml/xmlreader.h>  
  3.   
  4. @interface NewsFeedParser : NSObject {  
  5.       
  6. }  
  7.   
  8. +(NSMutableArray*) parseFeedFromUrl:(NSString *) url;  
  9.   
  10. @end  

 

NewsFeedParser.m

C代码  收藏代码
  1. #import "NewsFeedParser.h"  
  2.   
  3. @implementation NewsFeedParser  
  4.   
  5. +(NSMutableArray*) parseFeedFromUrl:(NSString *) url  
  6. {  
  7.     NSMutableArray *itemsArray = [NSMutableArray array];  
  8.       
  9.     //NSLog(@"NewsFeedParser:%@ begin\n", url);  
  10.       
  11.     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];  
  12.     NSURLResponse *response;  
  13.     NSError *error;  
  14.       
  15.     NSData *xmlData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response  
  16.                                                         error:&error];  
  17.     xmlTextReaderPtr reader = xmlReaderForMemory([xmlData bytes],   
  18.                                                  [xmlData length],   
  19.                                                  nil, nil,   
  20.                                                  (XML_PARSE_NOENT|XML_PARSE_NOBLANKS | XML_PARSE_NOCDATA | XML_PARSE_NOERROR | XML_PARSE_NOWARNING));  
  21.                                                    
  22.         if (!reader) {  
  23.         NSLog(@"Failed to load xmlreader");  
  24.         return itemsArray;  
  25.     }  
  26.     NSString *currentTagName = nil;  
  27.       
  28.     NSDictionary *currentItem = nil;  
  29.       
  30.       
  31.     NSString *currentTagValue = nil;  
  32.     bool itemStarted = false;  
  33.     bool authorStarted = false;  
  34.     bool categoryStarted = false;  
  35.     char* temp;  
  36.       
  37.     while (true) {  
  38.         if (!xmlTextReaderRead(reader))   
  39.             break;  
  40.         int type = xmlTextReaderNodeType(reader);  
  41.         switch (type) {  
  42.             case XML_READER_TYPE_END_ELEMENT:  
  43.                   
  44.                 temp =  (char*)xmlTextReaderConstName(reader);  
  45.                 currentTagName = [NSString stringWithCString:temp   
  46.                                                     encoding:NSUTF8StringEncoding];  
  47.                   
  48.                 if ([currentTagName isEqualToString:@"item"]) {  
  49.                     itemStarted = false;  
  50.                 }     
  51.                 continue;  
  52.                   
  53.             case XML_READER_TYPE_ELEMENT:  
  54.                 //We are starting an element  
  55.                 temp =  (char*)xmlTextReaderConstName(reader);  
  56.                 currentTagName = [NSString stringWithCString:temp   
  57.                                                     encoding:NSUTF8StringEncoding];  
  58.                   
  59.                   
  60.                 if ([currentTagName isEqualToString:@"item"]) {  
  61.                     //NSLog(@"Item begin\n");  
  62.                     currentItem = [NSMutableDictionary dictionary];  
  63.                     [itemsArray addObject:currentItem];  
  64.                     itemStarted = true;  
  65.                     authorStarted = false;  
  66.                     categoryStarted = false;  
  67.                 }  
  68.                   
  69.                 if([currentTagName isEqualToString:@"author"]){  
  70.                     authorStarted = true;  
  71.                     categoryStarted = false;  
  72.                 }  
  73.                   
  74.                 if([currentTagName isEqualToString:@"category"]){  
  75.                     categoryStarted = true;  
  76.                     authorStarted = false;  
  77.                 }  
  78.   
  79.                 if(itemStarted == true && [currentTagName isEqualToString:@"media:content"])  
  80.                 {  
  81.                     temp = (char*)xmlTextReaderGetAttribute(reader,"url");  
  82.                       
  83.                     currentTagValue = [NSString stringWithCString:temp   
  84.                                                          encoding:NSUTF8StringEncoding];  
  85.                       
  86.                     [currentItem setValue:currentTagValue forKey:currentTagName];  
  87.                     //NSLog(@"%@ - %@\n", currentTagName, currentTagValue);  
  88.   
  89.                     currentTagValue = nil;  
  90.   
  91.                 }  
  92.                   
  93.                 continue;  
  94.   
  95.             case XML_READER_TYPE_TEXT:  
  96.                 //The current tag has a text value, stick it into the current person  
  97.                 if(itemStarted == false)  
  98.                     continue;  
  99.                   
  100.                 temp = (char*)xmlTextReaderConstValue(reader);  
  101.                 currentTagValue = [NSString stringWithCString:temp   
  102.                                                      encoding:NSUTF8StringEncoding];  
  103.                   
  104.                 //NSLog(@"%@ - %@\n", currentTagName, currentTagValue);  
  105.                   
  106.                 if([currentTagName isEqualToString:@"name"]){  
  107.                       
  108.                     if(authorStarted)  
  109.                         [currentItem setValue:currentTagValue forKey:@"author"];  
  110.                       
  111.                     if(categoryStarted)  
  112.                         [currentItem setValue:currentTagValue forKey:@"category"];  
  113.                       
  114.                 }  
  115.                 else{  
  116.                     [currentItem setValue:currentTagValue forKey:currentTagName];  
  117.                 }  
  118.                   
  119.                   
  120.                 currentTagValue = nil;  
  121.                 currentTagName = nil;  
  122.                 continue;  
  123.                   
  124.             case XML_READER_TYPE_ATTRIBUTE:  
  125.                 //temp = (char*)xmlTextReaderConstValue(reader);  
  126.                 //NSLog(@"%s\n", temp);  
  127.             default:   
  128.                 continue;  
  129.         }  
  130.     }  
  131.       
  132.     //NSLog(@"NewsFeedParser:%@ done\n", url);  
  133.       
  134.     return itemsArray;  
  135.       
  136. }  
  137.   
  138. @end  

 

ViewController.m

Java代码  收藏代码
  1. #import "NewsFeedParser.h"  
  2.   
  3. -(void) loadMarketData{  
  4.    
  5.     dispatch_async(dispatch_get_global_queue(00), ^{  
  6.           
  7.         NSMutableArray *items = [NewsFeedParser parseFeedFromUrl:@"http://www.domain.com/feed/ipad/marketchart/main.rss"];  
  8.           
  9.         if([items count] == 0)  
  10.             return;  
  11.               
  12.         NSLog(@"Title => %@", [[items objectAtIndex:0] objectForKey:@"title"]);  
  13.         NSLog(@"Last=> %@", [[items objectAtIndex:0] objectForKey:@"last"]);  
  14.         NSLog(@"Change=> %@", [[items objectAtIndex:0] objectForKey:@"change"]);  
  15.   
  16.   
  17.     });          
  18. }  

 

其他一些方法:

 

 

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

 

C代码  收藏代码
  1. <libxml/xmlreader.h>  
  2.   
  3. xmlTextReader xmlTextReaderPtr //XmlReader的结构体及其指针  
  4.   
  5. xmlTextReaderPtr xmlReaderForFile (const char * filename, const char * encoding, int options) //打开一个xml文件并返回xmlreader对象,准备开始分析.  
  6.   
  7. int xmlTextReaderRead (xmlTextReaderPtr reader) //读取下一个节点(注意,是下一个,不是下一个同层节点)  
  8.   
  9. int xmlTextReaderNext (xmlTextReaderPtr reader) //读取下一个同层节点  
  10.   
  11. int xmlTextReaderNodeType (xmlTextReaderPtr reader) //判断当前节点的类型  
  12.   
  13. xmlChar *xmlTextReaderGetAttribute (xmlTextReaderPtr reader, const xmlChar * name) //获取当前节点的指定属性  
  14.   
  15. xmlChar *xmlTextReaderReadString (xmlTextReaderPtr reader) //读取当前节点下的text  
  16.   
  17. xmlNodePtr xmlTextReaderExpand (xmlTextReaderPtr reader) //将当前节点展开成一个节点对象(慎用)  
  18.   
  19. int xmlTextReaderHasValue (xmlTextReaderPtr reader) //判断当前节点是否有text值  
  20.   
  21. int xmlTextReaderHasAttributes (xmlTextReaderPtr reader) //判断当前节点是否包含属性  
  22.   
  23. int xmlTextReaderMoveToAttribute (xmlTextReaderPtr reader, const xmlChar * name) //移动指针到当前节点的指定属性名的属性  
  24.   
  25. int xmlTextReaderMoveToAttributeNo (xmlTextReaderPtr reader, int no) //移动指针到当前节点指定属性编号的属性  
  26.   
  27. int xmlTextReaderMoveToElement (xmlTextReaderPtr reader) //将指针移会当前节点  
  28.   
  29. int xmlTextReaderMoveToFirstAttribute (xmlTextReaderPtr reader) //将指针移动到当前节点的第一个属性  
  30.   
  31. int xmlTextReaderMoveToNextAttribute (xmlTextReaderPtr reader) //将指针移动到当前节点的下一个属性  
  32.   
  33. xmlChar *xmlTextReaderName (xmlTextReaderPtr reader) //返回当前节点的名字  

 

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

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

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

C代码  收藏代码
  1. xmlChar* xmlStrcat (xmlChar *cur, const xmlChar * add)  
  2.    
  3. const xmlChar *xmlStrchr(const xmlChar * str, xmlChar val)  
  4.    
  5. int xmlStrcmp (const xmlChar * str1, const xmlChar * str2)  
  6.    
  7. int xmlStrlen (const xmlChar * str)  
  8.    
  9. xmlChar *xmlStrncat (xmlChar * cur, const xmlChar * add, int len)  
  10.    
  11. int xmlStrncmp (const xmlChar * str1, const xmlChar * str2, int len)  
  12.   
  13. const xmlChar *xmlStrstr (const xmlChar * str, const xmlChar * val)  

 

更多函数大家可以参考

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

抱歉!评论已关闭.