zoukankan      html  css  js  c++  java
  • 通过NSXMLParser来解析XML

    NSXMLParser 使用 delegate 模型来解析 XML 内容的。下面我们来创建一个 XML 文 件,文件中包含如下内容(在工程中保存为 MyXML.xml): 
    <?xml version="1.0" encoding="UTF-8"?>
    <root>
    <person id="1">
        <firstName>zhang</firstName>
        <lastName>san</lastName>
        <age>51</age>
    </person>
    
    <person id="2">
        <firstName>li</firstName>
        <lastName>si</lastName>
        <age>61</age>
    </person>
    
    </root>

    #import <UIKit/UIKit.h> @interface AppDelegate : UIResponder <UIApplicationDelegate,NSXMLParserDelegate> @property (strong, nonatomic) UIWindow *window; @property (nonatomic, strong) NSXMLParser *xmlParser; @end
    可以看到,我定义了一个XML parser app delegate,并且尊循NSXMLParserDelegate协 议,该协议是作为 NSXMLParser 解析 xml 需要用到的 delegate。现在从磁盘中读取 MyXML.xml 文件,并将其传递给 XML 解析器: 
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        //找到文件路径
        NSString *xmlFilePath = [[NSBundle mainBundle]pathForResource:@"MyXML" ofType:@"xml"];
        NSData *xml = [[NSData alloc]initWithContentsOfFile:xmlFilePath];
        self.xmlParser = [[NSXMLParser alloc]initWithData:xml];
        self.xmlParser.delegate = self;
        if ([self.xmlParser parse]) {
            NSLog(@"The XML is parsed");
        }else{
            NSLog(@"Failed to parse the XML");
        }
        return YES;
    } 
      首先把文件内容读取到一个 NSData 实例对象中,然后使用 initWithData:来初始化我们 的 XML parser,并把我们从 xml 文件中读取出来的数据传递进去。之后我们可以调用 XML parser 的 parse 方法来开始解析处理。这个方法会阻塞当前线程,直至解析处理结束。如果 你需要解析的 XML 文件非常大,强烈建议使用一个全局的 dispatch 队列来进行解析。

      为了解析 XML 文件,我们需要了解定义在 NSXMLParserDelegate 协议中的代理方法和它们的职责: 

      parserDidStartDocument:
      解析开始的时候调用该方法。
      
      parserDidEndDocument:
      解析结束的时候调用该方法。

      parser:didStartElement:namespaceURI:qualifiedName:attributes:

      在 XML document 中,当解析器在解析的时候遇到了一个新的 element 时会被调用该方法。

     

      parser:didEndElement:namespaceURI:qualifiedName:

      当前节点结束之后会调用。

     

      parser:foundCharacters:

      当解析器在解析文档内容的时候被调用。

     
    在使用这些 delegate 方法的时候,我们可以为 XML 对象创建一个对象模型。下面我们定义一个对象来代表 XML element,类名叫做 XMLElement,代码如下: 
    #import <Foundation/Foundation.h>
    
    @interface XMLElement : NSObject
    @property (nonatomic, strong)NSString *name;
    @property (nonatomic, strong)NSString *text;
    @property (nonatomic, strong)NSDictionary *attributes;
    @property (nonatomic, strong)NSMutableArray *subElements;
    @property (nonatomic, weak) XMLElement *parent;
    @end
    

    .m

    #import "XMLElement.h"
    
    @implementation XMLElement
    - (NSMutableArray *)subElements{
        //get方法 懒加载
        if (_subElements == nil) {
            _subElements = [[NSMutableArray alloc]init];
        }
        return _subElements;
    }
    @end
      我只想当访问 subElements 数组的时候,如果该数组是 nil,才进行初始化。因此我把这个属性的内存分配和初始化代码放到了它的getter方法中。如果说一个XML element没有子 elements,那么我们永远都不会使用到这个属性,因此这里也就不会为那个 element 分配内存和进行初始化工作。这种技术叫做 lazy allocation。 (懒加载)
      现在我们定义一个 XMLElement 实例,叫做 rootElement。我们的计划是开始解析处 理,向下获取 XML 文件内容并使用 delegate 方法进行解析,直至成功解析完整个文件。
    #import <UIKit/UIKit.h>
    @class XMLElement;
    @interface AppDelegate : UIResponder <UIApplicationDelegate,NSXMLParserDelegate>
    
    @property (strong, nonatomic) UIWindow *window;
    @property (nonatomic, strong) NSXMLParser *xmlParser;
    @property (nonatomic, strong) XMLElement *rootElement;
    @property (nonatomic, strong) XMLElement *currentElementPointer;
    @end
    
    开始解析处理。我们想要关注的第一个方法就是 parserDidStartDocument:方 法。在这个方法中,我们简单的重置一切: 
    //开始解析,重置
    - (void)parserDidStartDocument:(NSXMLParser *)parser{
        self.rootElement = nil;
        self.currentElementPointer = nil;
    }
    下一个方法就是 parser:didStartElement:namespaceURI:qualifiedName:attributes:方法。在 这个方法中,如果root element没有被创建,会被创建,并且开始解析一个新的element,我 们会计算它在 XML 结构中的位置,并在当前 element 中添加一个新的 element。 
    - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
        if (self.rootElement == nil) {
            self.rootElement = [[XMLElement alloc]init];
            self.currentElementPointer = self.rootElement;
        }else{
            XMLElement *newElement = [[XMLElement alloc]init];
            newElement.parent = self.currentElementPointer;
            [self.currentElementPointer.subElements addObject:newElement];
            self.currentElementPointer = newElement;
        }
        self.currentElementPointer.name = elementName;
        self.currentElementPointer.attributes = attributeDict;
    }
    
    下一步,就是 parser:foundCharacters: 这个方法了。这个方法将会在解析 element 的时 候调用多次,因此我们需要确保已经为多次进入该方法做好了准备。例如,如果一个 element 的文本有 4000 个字符长度,解析器在第一次解析时,最多只能解析 1000 个字符, 之后在解析当前 element 时,调用 parser:foundCharacters:方法,每次都是 1000,因此需要 4 次: 
    - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
        if ([self.currentElementPointer.text length] > 0) {
            self.currentElementPointer.text = [self.currentElementPointer.text stringByAppendingString:string];
        }else{
            self.currentElementPointer.text = string;
        }
    }
    
    下一个需要关注的方法就是 parser:didEndElement:namespaceURI:qualifiedName:方法,当 解析至某个 element 尾部时,会调用该方法。在这里,我们只需要把当前 element 指针指向 当前 element 的上一级: 
    - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
        self.currentElementPointer = self.currentElementPointer.parent;
    }
    
    最终,我们需要处理 parserDidEndDocument 这个方法。我们需要 dispose currentElementPointe 属性。 
    - (void)parserDidEndDocument:(NSXMLParser *)parser{
        self.currentElementPointer = nil;
    }
    
    上面就是所有的实现内容,现在你就可以使用 rootElement 属性来遍历 XML 结构了 
  • 相关阅读:
    C#通信学习(一)
    ms sql server 大批量导入
    PostgreSQL
    服务器性能指标有哪些
    C#一些需要注意的点(中级)
    JSON.parse与eval区别
    NDK编程中如何在C文件中打印调试信息
    Stack switching mechanism in a computer system
    Weex 相关文章收集
    JavaScript HTML DOM 元素(节点)
  • 原文地址:https://www.cnblogs.com/safiri/p/4155442.html
Copyright © 2011-2022 走看看