iOS 解析xml之——将XML转化为树demo

本人第一次发博文,不当之处请多多见谅。 解析xml的方法有很多种,最简单的是用系统提供的 比如要解析这么个xml, 命名为:trainlog.xml
<?xml version="1.0" encoding="utf-8"?>

<ArrayOfAnyType>
    
    <anyType xsi:type="JNXL_Struct_ZLGL"><ResourceID>L0000017</ResourceID><Name>Story time</Name><FtpPath>/lgftp/资源库/一年级/L0000017/Story time.wlg</FtpPath><LevelID>1</LevelID><SkillType>1</SkillType><TrainMode>AC</TrainMode><Score>-1</Score><StudyDate/><TimeLength>1</TimeLength></anyType>
    
    <anyType xsi:type="JNXL_Struct_ZLGL"><ResourceID>L0000018</ResourceID><Name>Let's sing</Name><FtpPath>/lgftp/资源库/一年级/L0000018/Let's sing.wlg</FtpPath><LevelID>1</LevelID><SkillType>1</SkillType><TrainMode>AC</TrainMode><Score>-1</Score><StudyDate/><TimeLength>0</TimeLength></anyType>

</ArrayOfAnyType>

可以用以下的方法直接一个个的解析出来

- (void)viewDidLoad
{
    [super viewDidLoad];
    ArrayAnyType=[[NSMutableArray alloc] init];
    NSXMLParser *xmlRead;
    NSString *path = [[NSBundle mainBundle] pathForResource:@"trainlog" ofType:@"xml"];
    NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:path];
    NSData *data = [file readDataToEndOfFile];//得到xml文件
    [file closeFile];
    xmlRead = [[NSXMLParser alloc] initWithData:data];//初始化NSXMLParser对象
    [data release];
    [xmlRead setDelegate:self];//设置NSXMLParser对象的解析方法代理
    BOOL success = [xmlRead parse];//调用代理解析NSXMLParser对象,看解析是否成功
    NSLog(@"success %d",success);
 
	// Do any additional setup after loading the view, typically from a nib.
}

//解析器,从两个结点之间读取内容
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
    NSLog(@"foundCharacters:%@",string);    
}

//获得结点结尾的值
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
    NSLog(@"foundCharacters:%@",elementName);
}


-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
     NSLog(@"didStartElement: %@",elementName);
}

但是面对复杂结构的xml 就不得不自己写相应的解析类了,而怎样使得解析的高效而且准确就是现在要解决的问题,用dom的方式是把文档全部导入内存,然后根据结点去查找,sax方式的话目前没有研究过不知道哪位大神能够解答写,我目前采用的是将xml转化为树,即利用以上系统解析的过程,自己一边创建一棵树,然后来查找树中叶子结点的内容。这个思路也借鉴了之前一些大神的code,这里根据自己的具体情况,做了个demo。现在开始新建一个工程,名字自定义吧,要完成以下四个步骤。

1. 创建TreeNode 类 
2. 创建XMLParser类 
3. 创建自己需要解读出来的类,我这里是AnyTypeCls类 
4. 在viewController中实现调用自己写的方法。 
下面贴代码了


// TreeNode.h

//
//  HBXMLParser.h
//  XMLParserDemo
 

#import <Foundation/Foundation.h>

#import <CoreFoundation/CoreFoundation.h>
@interface TreeNode : NSObject
{
    TreeNode        *parent;
    NSMutableArray  *children;
    NSString        *key;
    NSString        *leafvalue;
}
@property (nonatomic, retain)   TreeNode        *parent;
@property (nonatomic, retain)   NSMutableArray  *children;
@property (nonatomic, retain)   NSString        *key;
@property (nonatomic, retain)   NSString        *leafvalue;
@property (nonatomic, readonly) BOOL            isLeaf;
@property (nonatomic, readonly) BOOL            hasLeafValue;
@property (nonatomic, readonly) NSArray         *keys;
@property (nonatomic, readonly) NSArray         *allKeys;
@property (nonatomic, readonly) NSArray         *uniqKeys;
@property (nonatomic, readonly) NSArray         *uniqAllKeys;
@property (nonatomic, readonly) NSArray         *leaves;
@property (nonatomic, readonly) NSArray         *allLeaves;
@property (nonatomic, readonly) NSString        *dump;
+ (TreeNode *) treeNode;
- (NSString *) dump;
- (void) teardown;
// Leaf Utils
- (BOOL) isLeaf;
- (BOOL) hasLeafValue;
- (NSArray *) leaves;
- (NSArray *) allLeaves;
// Key Utils
- (NSArray *) keys;
- (NSArray *) allKeys;
- (NSArray *) uniqKeys;
- (NSArray *) uniqAllKeys;
// Search Utils
- (TreeNode *) objectForKey: (NSString *) aKey;
- (NSString *) leafForKey: (NSString *) aKey;
- (NSMutableArray *) objectsForKey: (NSString *) aKey;
- (NSMutableArray *) leavesForKey: (NSString *) aKey;
- (TreeNode *) objectForKeys: (NSArray *) keys;
- (NSString *) leafForKeys: (NSArray *) keys;

// Convert Utils
- (NSMutableDictionary *) dictionaryForChildren;
@end

//TreeNode.m 代码如下

/

/*
    将xml转化为树
    解析xml的算法思想(利用堆栈进栈出栈的原理)
    将从XMLParser得到的数据进行整理
 
 */

#import "TreeNode.h"
// String stripper utility macro
#define STRIP(X)    [X stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]
@implementation TreeNode
@synthesize parent;
@synthesize children;
@synthesize key;
@synthesize leafvalue;
#pragma mark Create and Initialize TreeNodes
- (TreeNode *) init
{
    if (self = [super init])
    {
        self.key = nil;
        self.leafvalue = nil;
        self.parent = nil;
        self.children = nil;
    }
    return self;
}
+ (TreeNode *) treeNode
{
    return [[[self alloc] init] autorelease];
}
#pragma mark TreeNode type routines
- (BOOL) isLeaf
{
    return (self.children.count == 0);
}
- (BOOL) hasLeafValue
{
    return (self.leafvalue != nil);
}
#pragma mark TreeNode data recovery routines
// Return an array of child keys. No recursion
- (NSArray *) keys
{
    NSMutableArray *results = [NSMutableArray array];
    for (TreeNode *node in self.children) [results addObject:node.key];
    return results;
}
// Return an array of child keys with depth-first recursion.
- (NSArray *) allKeys
{
    NSMutableArray *results = [NSMutableArray array];
    for (TreeNode *node in self.children)
    {
        [results addObject:node.key];
        [results addObjectsFromArray:node.allKeys];
    }
    return results;
}
- (NSArray *) uniqArray: (NSArray *) anArray
{
    NSMutableArray *array = [NSMutableArray array];
    for (id object in [anArray sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)])
        if (![[array lastObject] isEqualToString:object]) [array addObject:object];
    return array;
}
// Return a sorted, uniq array of child keys. No recursion

- (NSArray *) uniqKeys
{
    return [self uniqArray:[self keys]];
}
// Return a sorted, uniq array of child keys. With depth-first recursion

- (NSArray *) uniqAllKeys
{
    return [self uniqArray:[self allKeys]];
}
// Return an array of child leaves. No recursion

- (NSArray *) leaves
{
    NSMutableArray *results = [NSMutableArray array];
    for (TreeNode *node in self.children) if (node.leafvalue) [results addObject:node.leafvalue];
    return results;
}
// Return an array of child leaves with depth-first recursion.

- (NSArray *) allLeaves
{
    NSMutableArray *results = [NSMutableArray array];
    for (TreeNode *node in self.children)
    {
        if (node.leafvalue) [results addObject:node.leafvalue];
        [results addObjectsFromArray:node.allLeaves];
    }
    return results;
}
#pragma mark TreeNode search and retrieve routines
// Return the first child that matches the key, searching recursively breadth first
- (TreeNode *) objectForKey: (NSString *) aKey
{
    TreeNode *result = nil;
    for (TreeNode *node in self.children)
        if ([node.key isEqualToString: aKey])
        {
            result = node;
            break;
        }
    if (result) return result;
    for (TreeNode *node in self.children)
    {
        result = [node objectForKey:aKey];
        if (result) break;
    }
    return result;
}
// Return the first leaf whose key is a match, searching recursively breadth first

- (NSString *) leafForKey: (NSString *) aKey
{
    TreeNode *node = [self objectForKey:aKey];
    return node.leafvalue;
}
// Return all children that match the key, including recursive depth first search.

- (NSMutableArray *) objectsForKey: (NSString *) aKey
{
    NSMutableArray *result = [NSMutableArray array];
    for (TreeNode *node in self.children)
    {
        if ([node.key isEqualToString: aKey]) [result addObject:node];
        [result addObjectsFromArray:[node objectsForKey:aKey]];
    }
    return result;
}
// Return all leaves that match the key, including recursive depth first search.

- (NSMutableArray *) leavesForKey: (NSString *) aKey
{
    NSMutableArray *result = [NSMutableArray array];
    for (TreeNode *node in [self objectsForKey:aKey])
        if (node.leafvalue)
            [result addObject:node.leafvalue];
    return result;
}
// Follow a key path that matches each first found branch, returning object

- (TreeNode *) objectForKeys: (NSArray *) keys

{
    if ([keys count] == 0) return self;
    NSMutableArray *nextArray = [NSMutableArray arrayWithArray:keys];
    [nextArray removeObjectAtIndex:0];
    for (TreeNode *node in self.children)
    {
        if ([node.key isEqualToString:[keys objectAtIndex:0]])
            return [node objectForKeys:nextArray];
    }
    return nil;
}
// Follow a key path that matches each first found branch, returning leaf

- (NSString *) leafForKeys: (NSArray *) keys
{
    TreeNode *node = [self objectForKeys:keys];
    return node.leafvalue;
}
#pragma mark output utilities
// Print out the tree

- (void) dumpAtIndent: (int) indent into:(NSMutableString *) outstring
{
    for (int i = 0; i < indent; i++) [outstring appendString:@"--"];
    [outstring appendFormat:@"[%2d] Key: %@ ", indent, key];
    if (self.leafvalue) [outstring appendFormat:@"(%@)", STRIP(self.leafvalue)];
    [outstring appendString:@"\n"];
    for (TreeNode *node in self.children) [node dumpAtIndent:indent + 1 into: outstring];
}
- (NSString *) dump
{
    NSMutableString *outstring = [[NSMutableString alloc] init];
    [self dumpAtIndent:0 into:outstring];
    return [outstring autorelease];
}
#pragma mark conversion utilities
// When you're sure you're the parent of all leaves, transform to a dictionary

- (NSMutableDictionary *) dictionaryForChildren
{
    NSMutableDictionary *results = [NSMutableDictionary dictionary];
    for (TreeNode *node in self.children)
        if (node.hasLeafValue) [results setObject:node.leafvalue forKey:node.key];
    return results;
}
#pragma mark invocation forwarding
// Invocation Forwarding lets node act like array

- (id)forwardingTargetForSelector:(SEL)sel
{
    if ([self.children respondsToSelector:sel]) return self.children;
     return nil;
}
// Extend selector compliance
- (BOOL)respondsToSelector:(SEL)aSelector

{
    if ( [super respondsToSelector:aSelector] ) return YES;
    if ([self.children respondsToSelector:aSelector]) return YES;
    return NO;
}
// Allow posing as NSArray class for children
- (BOOL)isKindOfClass:(Class)aClass

{
    if (aClass == [TreeNode class]) return YES;
    if ([super isKindOfClass:aClass]) return YES;
    if ([self.children isKindOfClass:aClass]) return YES;
    return NO;
}
#pragma mark cleanup

- (void) teardown
{
    for (TreeNode *node in [[self.children copy] autorelease]) [node teardown];
    [self.parent.children removeObject:self];
    self.parent = nil;
}

- (void) dealloc
{
    self.parent = nil;
    self.children = nil;
    self.key = nil;
    self.leafvalue = nil;
    [super dealloc];
}
@end

//XMLParser.h 代码如下

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

//XMLParser.m 代码如下:

//
//  XMLParser.m
//  XMLParserDemo
//
 
//

#import "XMLParser.h"
#import "TreeNode.h"
@implementation XMLParser

static XMLParser *sharedInstance = nil;
// Use just one parser instance at any time
+(XMLParser *) sharedInstance
{
    if(!sharedInstance) {
        sharedInstance = [[self alloc] init];
    }
    return sharedInstance;
}
// Parser returns the tree root. You may have to go down one node to the real results
- (TreeNode *) parse: (NSXMLParser *) parser
{
    stack = [NSMutableArray array];
    TreeNode *root = [TreeNode treeNode];
    root.parent = nil;
    root.leafvalue = nil;
    root.children = [NSMutableArray array];
    [stack addObject:root];
    [parser setDelegate:self];
    [parser parse];
    [parser release];
    // pop down to real root
    TreeNode *realroot = [[root children] lastObject];
    root.children = nil;
    root.parent = nil;
    root.leafvalue = nil;
    root.key = nil;
    realroot.parent = nil;
    return realroot;
}

- (TreeNode *)parseXMLFromURL: (NSURL *) url
{
    TreeNode *results;
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
    results = [self parse:parser];
    [pool drain];
    return results;
}

- (TreeNode *)parseXMLFromLocalPath: (NSString *) Xmlpath
{
    TreeNode *results;
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    //NSString *path = [[NSBundle mainBundle] pathForResource:@"trainlog" ofType:@"xml"];
    NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:Xmlpath];
    NSData *data = [file readDataToEndOfFile];//得到xml文件
    [file closeFile];
    NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
    //= [[NSXMLParser alloc] init] // [[NSXMLParser alloc] initWithContentsOfURL:url];
    results = [self parse:parser];
    [pool drain];
    return results;
}

- (TreeNode *)parseXMLFromData: (NSData *) data
{
    TreeNode *results;
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
    results = [self parse:parser];
    [pool drain];
    return results;
}
// Descend to a new element

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)
namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
    if (qName) elementName = qName;
    TreeNode *leaf = [TreeNode treeNode];
    leaf.parent = [stack lastObject];
    [(NSMutableArray *)[[stack lastObject] children] addObject:leaf];
    leaf.key = [NSString stringWithString:elementName];
    leaf.leafvalue = nil;
    leaf.children = [NSMutableArray array];
    [stack addObject:leaf];
    //NSLog(@"didStartElement %@",elementName);
}
// Pop after finishing element

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
    [stack removeLastObject];
    //NSLog(@"didEndElement %@",elementName);
}
// Reached a leaf

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
    if (![[stack lastObject] leafvalue])
    {
        [[stack lastObject] setLeafvalue:[NSString stringWithString:string]];
        return;
    }
    [[stack lastObject] setLeafvalue:[NSString stringWithFormat:@"%@%@", [[stack lastObject] leafvalue], string]];
    //NSLog(@"foundCharacters %@",string);
}
@end

第三步:解析过程基本上写完了,下面是写自己需要保存到某个类,我这里是

//  AnyTypeCls.h

#import <Foundation/Foundation.h>

@interface AnyTypeCls : NSObject
{
    NSString *type;
    NSString * ResourceID;
    NSString *Name;
    NSString *FtpPath;
    NSString *LevelID;
    NSString *SkillType;
    NSString *TrainMode;
    NSString *Score;
    NSString *StudyDate;
    NSString *TimeLength;
    /*    <Name>Story time</Name><FtpPath>/lgftp/中小学资源库/一年级/声文同步L0000017/Story time.wlg</FtpPath><LevelID>1</LevelID><SkillType>1</SkillType><TrainMode>AC</TrainMode><Score>-1</Score><StudyDate/><TimeLength>1</TimeLength>*/
}
@property(nonatomic,retain) NSString *type;
@property(nonatomic,retain) NSString * ResourceID;
@property(nonatomic,retain) NSString *Name;
@property(nonatomic,retain) NSString *FtpPath;
@property(nonatomic,retain) NSString *LevelID;
@property(nonatomic,retain) NSString *SkillType;
@property(nonatomic,retain) NSString *TrainMode;
@property(nonatomic,retain) NSString *Score;
@property(nonatomic,retain) NSString *StudyDate;
@property(nonatomic,retain) NSString *TimeLength;

@end


// AnyTypeCls.m 代码清单:

#import "AnyTypeCls.h"
@implementation AnyTypeCls

@synthesize  type;
@synthesize  ResourceID;
@synthesize Name;
@synthesize FtpPath;
@synthesize LevelID;
@synthesize SkillType;
@synthesize TrainMode;
@synthesize Score;
@synthesize StudyDate;
@synthesize TimeLength;

-(NSString *)description
{
    NSString *des=[[NSString alloc] initWithFormat:@"%@, %@, %@,%@,%@,%@,%@,%@, %@",ResourceID, Name,FtpPath,LevelID,SkillType,TrainMode,Score,StudyDate,TimeLength ];
    return des;
}
@end
第四步:编写自己的调用函数,将自己的类填充

//ViewController.h 

#import <UIKit/UIKit.h>
@class AnyTypeCls;
@class XMLParser;
@interface ViewController : UIViewController 
{
    NSMutableArray *ArrayAnyType;
    XMLParser *parser;
}

@property(nonatomic,retain) NSMutableArray *ArrayAnyType;

@end

//ViewController.m 

#import "ViewController.h"
#import "AnyTypeCls.h"
#import "TreeNode.h"
#import "XMLParser.h"
@interface ViewController ()

@end

@implementation ViewController
@synthesize ArrayAnyType;

-(void)viewDidLoad
{
    NSString *filePath=[[NSBundle mainBundle] pathForResource:@"trainlog" ofType:@"xml"];
    ArrayAnyType=[[NSMutableArray alloc] init];
    //  NSURL * url = [[NSURL alloc] initWithString:filePath]; //@"http://10.5.23.117:4444/Login.xml"];
    if ([[NSFileManager defaultManager] fileExistsAtPath:filePath])
    {
        NSLog(@"文件存在");     
        parser=[[XMLParser alloc] init];
        TreeNode *node=[parser parseXMLFromLocalPath:filePath]; //[parser parseXMLFromData:data];
        NSInteger count=[node.allLeaves count];
        
        for (int i=0; i<count; i+=8) {
            AnyTypeCls *anytype=[[AnyTypeCls alloc] init];
            anytype.ResourceID=[node.allLeaves objectAtIndex:i];
            anytype.Name=[node.allLeaves objectAtIndex:i+1];
            anytype.FtpPath =[node.allLeaves objectAtIndex:i+2];
            anytype.LevelID=[node.allLeaves objectAtIndex:i+3];
            anytype.SkillType=[node.allLeaves objectAtIndex:i+4];
            anytype.TrainMode=[node.allLeaves objectAtIndex:i+5];
            anytype.Score=[node.allLeaves objectAtIndex:i+6];
            //anytype.StudyDate=@"";
            anytype.TimeLength=[node.allLeaves objectAtIndex:i+7];
            [ArrayAnyType addObject:anytype];
            //NSLog(@"%@",anytype);
         }        
        //NSLog(@"%@",result);
    }
    else
    {
        NSLog(@"文件不存在");
    //[node debugDescription];
    }
    NSLog(@"%@",[ArrayAnyType objectAtIndex:2]);
}













  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值