How to use NSXMLParser to parse parent-child elements that have the same name

后端 未结 3 1023
时光取名叫无心
时光取名叫无心 2020-11-29 00:17

Does anyone have some idea how to parse the following xml using event-driven model NSXMLParser class?


   Main 
  

        
相关标签:
3条回答
  • 2020-11-29 00:31

    A very easier way to solve it than the accepted answer, for short XML files:

    XML example:

    <cotacoes>
        <bovespa>
                <cotacao>50058</cotacao>
                <variacao>-0.16</variacao>
        </bovespa>
        <dolar>
                <cotacao>3.4610</cotacao>
                <variacao>+0.29</variacao>
        </dolar>
        <euro>
                <cotacao>3.7673</cotacao>
                <variacao>-0.25</variacao>
        </euro>
        <atualizacao>04/08/15 - 18:14</atualizacao>
    </cotacoes>
    

    Implement a counter:

    @implementation className{
        int parserCounter;
    }
    
    - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
    {
        parserCounter++;
    
        NSLog(@"%d: %@",contadorParser,string);
    
        if (parserCounter == 3) doAnythingFor3;
        if (parserCounter == 5) doAnythingFor5;
        if (parserCounter == 9) doAnythingFor9;
        if (parserCounter == 11) doAnythingFor11;
        if (parserCounter == 15) doAnythingFor15;
        if (parserCounter == 17) doAnythingFor17;
        if (parserCounter == 20) doAnythingFor20;
    
    }
    

    How will i know witch number is witch node ? By seeing the log. It will be something like:

    2015-08-04 23:36:08.070 Tesouro Direto[7252:1554402] 1:     
    2015-08-04 23:36:08.070 Tesouro Direto[7252:1554402] 2:     
    2015-08-04 23:36:08.071 Tesouro Direto[7252:1554402] 3:     50058
    2015-08-04 23:36:08.105 Tesouro Direto[7252:1554402] 4:     
    2015-08-04 23:36:08.105 Tesouro Direto[7252:1554402] 5:     -0.16
    2015-08-04 23:36:08.131 Tesouro Direto[7252:1554402] 6:     
    2015-08-04 23:36:08.132 Tesouro Direto[7252:1554402] 7:     
    2015-08-04 23:36:08.132 Tesouro Direto[7252:1554402] 8:     
    2015-08-04 23:36:08.132 Tesouro Direto[7252:1554402] 9:     3.4610
    2015-08-04 23:36:08.156 Tesouro Direto[7252:1554402] 10:    
    2015-08-04 23:36:08.156 Tesouro Direto[7252:1554402] 11:    +0.29   
    2015-08-04 23:36:08.180 Tesouro Direto[7252:1554402] 12:    
    2015-08-04 23:36:08.180 Tesouro Direto[7252:1554402] 13:    
    2015-08-04 23:36:08.180 Tesouro Direto[7252:1554402] 14:    
    2015-08-04 23:36:08.180 Tesouro Direto[7252:1554402] 15:    3.7673
    2015-08-04 23:36:08.203 Tesouro Direto[7252:1554402] 16:    
    2015-08-04 23:36:08.203 Tesouro Direto[7252:1554402] 17:    -0.25
    2015-08-04 23:36:08.226 Tesouro Direto[7252:1554402] 18:    
    2015-08-04 23:36:08.227 Tesouro Direto[7252:1554402] 19:    
    2015-08-04 23:36:08.227 Tesouro Direto[7252:1554402] 20:    04/08/15   - 18:14
    2015-08-04 23:36:08.227 Tesouro Direto[7252:1554402] 21: 
    

    The log will show you witch number is each node.

    0 讨论(0)
  • 2020-11-29 00:42
    - (NSInteger)columnNumber
    

    gives you the nesting level of NSXMLParser

    0 讨论(0)
  • 2020-11-29 00:47

    This is a common problem with parsers like this one, of "type SAX", where you have to manually keep track of the current depth of the XML tree you're in. The problem, as always, is that loading the entire tree in a DOM structure in memory can be impossible, depending on the size of the data you want to manipulate.

    The following code shows a class that does this job:

    #import <Foundation/Foundation.h>
    
    @interface Test : NSObject <NSXMLParserDelegate> 
    {
    @private
        NSXMLParser *xmlParser;
        NSInteger depth;
        NSMutableString *currentName;
        NSString *currentElement;
    }
    
    - (void)start;
    
    @end
    

    This is the implementation:

    #import "Test.h"
    
    @interface Test ()
    - (void)showCurrentDepth;
    @end
    
    
    @implementation Test
    
    - (void)dealloc
    {
        [currentElement release];
        [currentName release];
        [xmlParser release];
        [super dealloc];
    }
    
    - (void)start
    {
        NSString *xml = @"<?xml version=\"1.0\" encoding=\"UTF-8\" ?><Node><name>Main</name><Node><name>Child 1</name></Node><Node><name>Child 2</name></Node></Node>";
        xmlParser = [[NSXMLParser alloc] initWithData:[xml dataUsingEncoding:NSUTF8StringEncoding]];
        [xmlParser setDelegate:self];
        [xmlParser setShouldProcessNamespaces:NO];
        [xmlParser setShouldReportNamespacePrefixes:NO];
        [xmlParser setShouldResolveExternalEntities:NO];
        [xmlParser parse];
    
    }
    
    #pragma mark -
    #pragma mark NSXMLParserDelegate methods
    
    - (void)parserDidStartDocument:(NSXMLParser *)parser 
    {
        NSLog(@"Document started", nil);
        depth = 0;
        currentElement = nil;
    }
    
    - (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError 
    {
        NSLog(@"Error: %@", [parseError localizedDescription]);
    }
    
    - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName 
      namespaceURI:(NSString *)namespaceURI 
     qualifiedName:(NSString *)qName 
        attributes:(NSDictionary *)attributeDict
    {
        [currentElement release];
        currentElement = [elementName copy];
    
        if ([currentElement isEqualToString:@"Node"])
        {
            ++depth;
            [self showCurrentDepth];
        }
        else if ([currentElement isEqualToString:@"name"])
        {
            [currentName release];
            currentName = [[NSMutableString alloc] init];
        }
    }
    
    - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName 
      namespaceURI:(NSString *)namespaceURI 
     qualifiedName:(NSString *)qName
    {
    
        if ([elementName isEqualToString:@"Node"]) 
        {
            --depth;
            [self showCurrentDepth];
        }
        else if ([elementName isEqualToString:@"name"])
        {
            if (depth == 1)
            {
                NSLog(@"Outer name tag: %@", currentName);
            }
            else 
            {
                NSLog(@"Inner name tag: %@", currentName);
            }
        }
    }        
    
    - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
    {
        if ([currentElement isEqualToString:@"name"]) 
        {
            [currentName appendString:string];
        } 
    }
    
    - (void)parserDidEndDocument:(NSXMLParser *)parser 
    {
        NSLog(@"Document finished", nil);
    }
    
    #pragma mark -
    #pragma mark Private methods
    
    - (void)showCurrentDepth
    {
        NSLog(@"Current depth: %d", depth);
    }
    
    @end
    

    This is the result of running a command line tool that triggers the "start" method above:

    Document started
    Current depth: 1
    Outer name tag: Main
    Current depth: 2
    Inner name tag: Child 1
    Current depth: 1
    Current depth: 2
    Inner name tag: Child 2
    Current depth: 1
    Current depth: 0
    Document finished
    
    0 讨论(0)
提交回复
热议问题