代码之家  ›  专栏  ›  技术社区  ›  Hoang Pham

如何使用NSXMLParser解析具有相同名称的父子元素

  •  8
  • Hoang Pham  · 技术社区  · 15 年前

    有人知道如何使用事件驱动模型NSXMLParser类解析以下xml吗?

    <Node>
      <name> Main </name>
      <Node>
        <name> Child 1 </name>
      </Node>
    
      <Node>
        <name> Child 2 </name>
      </Node>
    </Node>
    

    3 回复  |  直到 13 年前
        1
  •  32
  •   Adrian Kosmaczewski    15 年前

    这是“SAX类型”解析器的一个常见问题,您必须手动跟踪所处XML树的当前深度。与往常一样,问题在于无法将整个树加载到内存中的DOM结构中,这取决于要操作的数据的大小。

    以下代码显示执行此作业的类:

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

    这就是实现:

    #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
    

    这是运行命令行工具触发上述“启动”方法的结果:

    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
    
        2
  •  6
  •   yasirmturk    12 年前
    - (NSInteger)columnNumber
    

    NSXMLParser

        3
  •  -1
  •   brbgyn    9 年前

    对于简短的XML文件,这是一种比公认答案更简单的解决方法:

    XML示例:

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

    实现一个计数器:

    @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;
    
    }
    

    我怎么知道女巫号码是女巫节点? 通过查看日志。它将类似于:

    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: 
    

    日志将显示每个节点的开关编号。