【问题标题】:How to use NSXMLParser to extract and group specific nodes from xml file in Objective-C/iOS?如何使用 NSXMLParser 从 Objective-C/iOS 中的 xml 文件中提取和分组特定节点?
【发布时间】:2011-12-30 18:56:46
【问题描述】:

鉴于此 XML 结构来自 (http://localhost:3000/route.xml):

<objects type="array">
  <object>
    <trip0>
     <departure>20:01</departure>
     <start>Place a</start>
     <end>Place b </end>
     <arrival>20:16</arrival>
     <how>Walking</how>
    </trip0>
  </object>
  <object>
    <trip1>
      <departure>20:16</departure>
      <start>Place b</start>
      <end>Place c </end>
      <arrival>20:32</arrival>
      <how>By car</how>
     </trip1>
  </object>
</objects> 

使用以下 Objective-C 代码:

视图的实现

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    // URL localhost for testing purposes
    NSURL *url = [[NSURL alloc] initWithString:@"http://localhost:3000/route.xml"];

    // Init parser
    NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
    [xmlParser setDelegate:self];   

    //Start parsing the XML file.
    BOOL success = [xmlParser parse];

    if(success)
        NSLog(@"No Errors");
    else
        NSLog(@"Errors !!!!!!!!E!!!");
}


      #pragma mark XMLParser delegate
    - (void)parserDidStartDocument:(NSXMLParser *)parser 
    {
        NSLog(@"Document started", nil);
       }


    - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
      namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
        attributes:(NSDictionary *)attributeDict {

        if([elementName isEqualToString:@"trip0"]) {
            //Initialize the array.
            NSLog(@"Found trip0 !");
        }

        NSLog(@"Processing Element: %@", elementName);
    }

    - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {

        NSLog(@"Processing Value: %@", string);

    }

我可以将其作为输出:

2011-11-16 19:34:06.006 SandboxTabBar[11754:11603] Processing Element: objects
2011-11-16 19:34:06.008 SandboxTabBar[11754:11603] Processing Value: 

2011-11-16 19:34:06.009 SandboxTabBar[11754:11603] Processing Element: object
2011-11-16 19:34:06.009 SandboxTabBar[11754:11603] Processing Value: 

2011-11-16 19:34:06.010 SandboxTabBar[11754:11603] Found trip0 !!
2011-11-16 19:34:06.010 SandboxTabBar[11754:11603] Processing Element: trip0
2011-11-16 19:34:06.011 SandboxTabBar[11754:11603] Processing Value: 

2011-11-16 19:34:06.011 SandboxTabBar[11754:11603] Processing Element: departure
2011-11-16 19:34:06.012 SandboxTabBar[11754:11603] Processing Value: 20:01
2011-11-16 19:34:06.012 SandboxTabBar[11754:11603] Processing Value: 

2011-11-16 19:34:06.013 SandboxTabBar[11754:11603] Processing Element: start
2011-11-16 19:34:06.013 SandboxTabBar[11754:11603] Processing Value: Place a
2011-11-16 19:34:06.014 SandboxTabBar[11754:11603] Processing Value: 

2011-11-16 19:34:06.015 SandboxTabBar[11754:11603] Processing Element: end
2011-11-16 19:34:06.015 SandboxTabBar[11754:11603] Processing Value: Place b
2011-11-16 19:34:06.207 SandboxTabBar[11754:11603] Processing Value: 

2011-11-16 19:34:06.208 SandboxTabBar[11754:11603] Processing Element: arrival
2011-11-16 19:34:06.209 SandboxTabBar[11754:11603] Processing Value: 20:16
2011-11-16 19:34:06.210 SandboxTabBar[11754:11603] Processing Value: 

2011-11-16 19:34:06.211 SandboxTabBar[11754:11603] Processing Element: how
2011-11-16 19:34:06.212 SandboxTabBar[11754:11603] Processing Value: walking
2011-11-16 19:34:06.213 SandboxTabBar[11754:11603] Processing Value:  15 min 
2011-11-16 19:34:06.214 SandboxTabBar[11754:11603] Processing Value: 

2011-11-16 19:34:06.215 SandboxTabBar[11754:11603] Processing Value: 

2011-11-16 19:34:06.216 SandboxTabBar[11754:11603] Processing Value: 

2011-11-16 19:34:06.217 SandboxTabBar[11754:11603] Processing Element: object
2011-11-16 19:34:06.218 SandboxTabBar[11754:11603] Processing Value: 

2011-11-16 19:34:06.219 SandboxTabBar[11754:11603] Processing Element: trip1
2011-11-16 19:34:06.220 SandboxTabBar[11754:11603] Processing Value: 

2011-11-16 19:34:06.221 SandboxTabBar[11754:11603] Processing Element: departure
2011-11-16 19:34:06.222 SandboxTabBar[11754:11603] Processing Value: 20:32
2011-11-16 19:34:06.223 SandboxTabBar[11754:11603] Processing Value:

2011-11-16 19:34:06.221 SandboxTabBar[11754:11603] Processing Element: start
2011-11-16 19:34:06.222 SandboxTabBar[11754:11603] Processing Value: Place b
2011-11-16 19:34:06.223 SandboxTabBar[11754:11603] Processing Value:

等等……

我想用这样的内容填充 UITableviews:

“Trip 0 的出发时间是 20:01 从 Place A 到 Place b,20:16 步行到达。”

“行程1的出发时间是20:16从B地到C地,20:32乘车到达”

必须有一种更简单的方法来从 XML 文件中选择和组合我需要的节点。

如何用给定的 XML 文件实现这样的结果?

【问题讨论】:

    标签: objective-c cocoa-touch uitableview ios5 nsxmlparser


    【解决方案1】:

    DOM 解析器让这类事情变得更容易,但这确实意味着 (a) 在 iOS 上选择一个支持 DOM 的库,弄清楚它是如何工作的,它的特性等等,以及 (b) 拥有整个 XML 文档在你解析它并填充你的表模型之前在内存中。在许多情况下,这些都不是什么大问题,但有时内存问题可能会迫使您远离 DOM。

    如果您想为您的应用避免这些潜在问题,使用 NSXMLParser 实现您想要的并不难。首先,定义一个代表“旅行”的类,并为该类提供每次旅行所需的属性(开始、结束、到达等)。然后在你的解析器委托类中定义一些 ivars 来保存一个可变的 Trip 对象数组、一个可以随时填充的“currentTrip”对象,以及一个可以用来捕获解析器扫描的字符的可变字符缓冲区。

    有了这些,您就可以在解析器委托逻辑中实现类似以下内容:

    - (void)parserDidStartDocument:(NSXMLParser *)parser 
    {
        NSLog(@"Document started", nil);
        allTrips = [[NSMutableArray alloc] init];
       }
    
    
    - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
      namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
        attributes:(NSDictionary *)attributeDict {
    
        if([elementName hasPrefix:@"trip"]) {
            NSLog(@"Found trip: %@ !", elementName);
            currentTrip = [[Trip alloc] initWithName:elementName];
        }
        else {
            characterBuffer = [[NSMutableString alloc] init];
        }
    
        NSLog(@"Processing Element: %@", elementName);
    }
    
    - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
    
        NSLog(@"Processing Value: %@", string);
        [characterBuffer appendString:string];
    }
    
    - (void)parser:(NSXMLParser *)parser 
     didEndElement:(NSString *)elementName 
      namespaceURI:(NSString *)namespaceURI 
     qualifiedName:(NSString *)qName {
    
        if([elementName hasPrefix:@"trip"]) {
            [allTrips addObject:currentTrip];
        }
        else if ([elementName isEqualToString:@"start"){
            // Set start value
            NSString *value = [characterBuffer stringByTrimmingCharactersInSet:[NSCharacterSet  whitespaceAndNewlineCharacterSet]];
            [currentTrip setStart:value];
        }
        // Handle each other trip property you care about with separate else if's
    
    }
    

    这只是你想要的基本代码结构,不一定优化。特别是,我没有包含任何版本来避免内存泄漏,如果您不使用 ARC,您将需要它。此外,我在每个元素的开头创建了一个新的 characterBuffer 对象,其中可能包含您关心的文本:这可能会更智能地完成,需要更多的关注和思考。不过你明白了。

    总的来说,这种方法可能有点乏味,但也不难,而且在某些情况下,它的性能比 DOM 解析要好得多,如果这对你的应用来说是一个因素的话。

    【讨论】:

    • 蒂姆,谢谢你的回答!我设法让它工作并对每次旅行的数据进行分组。每次记录属性时我只有一个问题,当登录到一个字符串时,属性之间似乎有很多空格。 F.e. : NSLog(@"Started at : %@, Start: %@", trip.departure, trip.start) 会产生类似“Started at: 20:01 -------------- ------------------ 开始:放置一个“.如何在 20:01 和 Start: Place a 之间删除过时的空白(标记为 ---)?
    • 我已经编辑了我上面的帖子,包括使用“stringByTrimmingCharactersInSet”。该更改应从您的值中删除多余的空格。
    • 它解决了我的问题,非常感谢您的帮助和时间!
    【解决方案2】:

    看起来您可以使用带有 XPath 的 DOM 解析器。 DOM 解析器允许您遍历 XML 树结构而不是解析整个事物,而 XPath 允许您查询和过滤节点。

    看看 Google 的 GDataXMLNode。这个解析器是实现这一点的简单方法之一,可以找到教程,例如http://www.raywenderlich.com/725/how-to-read-and-write-xml-documents-with-gdataxml

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-06
      • 2018-07-30
      • 2012-05-30
      • 1970-01-01
      • 1970-01-01
      • 2019-05-12
      相关资源
      最近更新 更多