了解iOS中的NSXMLParser

时间:2013-01-30 16:20:04

标签: ios nsxmlparser mkannotationview mapkit

我了解当前的NSXMLParser。我阅读了很多教程,但没有人能告诉我它是如何工作的。 StackOverflow上有一个教程?我的问题是在我的应用程序中使用KML读取结构并使用MKMapView显示

My Parser类看起来像:

#import <Foundation/Foundation.h>

@interface Parser : NSXMLParser

@property (nonatomic, strong) NSString *rowElementName; // this is the element name that identifies a new row of data in the XML
@property (nonatomic, strong) NSArray *attributeNames;  // this is the array of attributes we might want to retrieve for that element name
@property (nonatomic, strong) NSArray *elementNames;    // this is the list of sub element names for which we're retrieving values

@property (nonatomic, strong) NSMutableArray *items;    // after parsing, this is the array of parsed items

@end

#import "Parser.h"

@interface Parser () <NSXMLParserDelegate>

@property (nonatomic, strong) NSMutableDictionary *item;     // while parsing, this is the item currently being parsed
@property (nonatomic, strong) NSMutableString *elementValue; // this is the element within that item being parsed

@end

@implementation Parser

- (id)initWithContentsOfURL:(NSURL *)url
{
    self = [super initWithContentsOfURL:url];

    if (self)
    {
        self.delegate = self;
    }

    return self;
}

- (id)initWithData:(NSData *)data
{
    self = [super initWithData:data];

    if (self)
    {
        self.delegate = self;
    }

    return self;
}

- (id)initWithStream:(NSInputStream *)stream
{
    self = [super initWithStream:stream];

    if (self)
    {
        self.delegate = self;
    }

    return self;
}

#pragma mark - NSXMLParserDelegate methods

- (void)parserDidStartDocument:(NSXMLParser *)parser
{
    self.items = [[NSMutableArray alloc] init];

    if (!self.rowElementName)
        NSLog(@"%s Warning: Failed to specify row identifier element name", __FUNCTION__);
}

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
    if ([elementName isEqualToString:self.rowElementName])
    {
        self.item  = [[NSMutableDictionary alloc] init];

        for (NSString *attributeName in self.attributeNames)
        {
            id attributeValue = [attributeDict valueForKey:attributeName];
            if (attributeValue)
                [self.item setObject:attributeValue forKey:attributeName];
        }
    }
    else if ([self.elementNames containsObject:elementName])
    {
        self.elementValue = [[NSMutableString alloc] init];
    }
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
    if (self.elementValue)
    {
        [self.elementValue appendString:string];
    }
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
    if ([elementName isEqualToString:self.rowElementName])
    {
        [self.items addObject:self.item];
        self.item = nil;
    }
    else if ([self.elementNames containsObject:elementName])
    {
        [self.item setValue:self.elementValue forKey:elementName];
        self.elementValue = nil;
    }
}

@end

rob

创建

我的XML文件:

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.1">
<Document>
    <name>Filename.kml</name>
    <Style id="style1">
        <IconStyle>
            <Icon>
                <href>http://imageshack.us/a/img825/9079/pinvi.png</href>
            </Icon>
        </IconStyle>
    </Style>
    <Placemark>
        <name><![CDATA[Blankenese]]></name>
        <Snippet><![CDATA[Blankeneser Bahnhofstr. 9 22587 Hamburg +49-(0)40-866 06 50 +49-(0)40-86 60 65 60]]></Snippet>
        <description><![CDATA[<img src="http://www.engelvoelkers.com/shops/de-blankenese-res.jpg"><br/>Blankeneser Bahnhofstr. 9<br/>22587 Hamburg<br/>Telefon: +49-(0)40-866 06 50<br/>Fax: +49-(0)40-86 60 65 60<br/><a href="http://www.engelvoelkers.com/elbe">Website</a><br/>E-Mail: Blankenese@engelvoelkers.com]]></description>
        <styleUrl>#style1</styleUrl>
        <Point>
            <coordinates>9.811470,53.559441</coordinates>
        </Point>
    </Placemark>
</Document>
</kml>

我的目标是获取<description>标记中的所有信息并将其显示为Google-Maps所做的enter image description here

不完全相似。

但首先我需要知道如何使用Parser

最好的问候CTS

2 个答案:

答案 0 :(得分:16)

这个问题有两个根本不同的组件,解析和注释地图。我将在这里专注于地图注释,因为我认为我在这里讨论了解析问题:Try to load a created Map in MKMapView。但是,在这个答案的最后,如果您只是试图搂住NSXMLParser,我会包含对Apple解析文档的一些引用。

注释地图

在iPhone上映射应用程序的常见模式是不在地图视图本身上显示包含丰富内容的popover,而是由于iPhone的有限空间,只显示标准标注,但设置{{ 1}}是一个披露指标,如果你点击它,将转移到具有细节的下一个视图。因此,通过使用rightCalloutAccessoryView方法,您可以使用UIMapViewDelegate表示:

mapView:viewForAnnotation:

这会产生以下用户界面:

right callout accessory

然后你可以像- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation { MKAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"loc"]; annotationView.canShowCallout = YES; annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure]; return annotationView; } 那样:

mapView:annotationView:calloutAccessoryControlTapped:

您可以使用它来转到您的详细信息屏幕。 (我只是对带有Web视图的视图控制器进行模态segue,在- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control { [self performSegueWithIdentifier:@"DetailsIphone" sender:view]; } 中传递注释,而prepareForSegue正在抓取html等。这里的详细信息不起眼。我假设您可以转换到您自己的详细信息屏幕并设计比这个快速和脏的Web视图更漂亮的东西......我只是在演示我们可以从KML文件中获取地标的HTML):

iPhone details screen

所以,虽然iPhone真的不应该在地图上使用弹出窗口,但在iPad上你可以使用它们。您可以以类似的方式创建viewDidLoad(尽管可能使用“信息”按钮而不是详细信息披露):

iPad right callout accessory

但是在这里你可以让rightCalloutAccessoryView实际生成弹出窗口,而不是进行模态转换:

mapView:annotationView:calloutAccessoryControlTapped:

产生:

iPad popover

顺便说一句,这大致近似于iPad Maps应用程序的工作方式(当您点击某个图钉时,它会显示带有“信息”按钮的标注),如果您再点击信息按钮,则会显示你带有细节的popover。

或者,您可以点击针脚直接转到弹出窗口,绕过介入的标注。但是,要做到这一点,首先必须在注释视图上禁用标注:

- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
    //CGRect frame = view.frame;
    [mapView deselectAnnotation:view.annotation animated:YES];

    DetailsViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:@"DetailsPopover"];
    controller.annotation = view.annotation;
    self.popover = [[UIPopoverController alloc] initWithContentViewController:controller];
    self.popover.delegate = self;
    [self.popover presentPopoverFromRect:view.frame
                                  inView:view.superview
                permittedArrowDirections:UIPopoverArrowDirectionAny
                                animated:YES];
}

但是你必须回复- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation { MKAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"loc"]; annotationView.canShowCallout = NO; return annotationView; }

mapView:didSelectAnnotationView:

理论上,你可以在iPhone上做这样的事情,但由于你不能使用- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view { [mapView deselectAnnotation:view.annotation animated:YES]; DetailsViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:@"DetailsPopover"]; controller.annotation = view.annotation; self.popover = [[UIPopoverController alloc] initWithContentViewController:controller]; self.popover.delegate = self; [self.popover presentPopoverFromRect:view.frame inView:view.superview permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; } ,你必须使用一些第三方弹出窗口(或自己编写)。我听说有些人声称Apple拒绝使用popover视图的iPhone应用程序,虽然我既不能确认,也不能说这是否是一个硬性规则。我只知道Apple和谷歌iPhone地图应用程序不会在iPhone地图应用程序上使用大型弹出窗口视图(Apple转向另一种视图,Google将其显示在屏幕底部)。如果你考虑一下,如果引脚位于中心位置并且你试图生成一个指向该引脚的大型弹出窗口,它可能会变得狭窄。

无论如何,这些是使用UIPopoverController设置和/或停用rightCalloutAccessoryView并直接显示弹出广告的选项。


解析引用:

地图视图标注参考:

答案 1 :(得分:1)

Parser的工作原理如下,打开root标签,然后搜索子标签。如果没有嵌套的标签,则会读取数据,此处您可以选择如何保存数据。还有许多其他解析器可用。浏览gDataXMLParser。我已经使用它并且工作得很好,并且如果有嵌套标签,请确保以递归方式调用解析器。 如果您正在寻找特定的标签,请使用该字符串查找子字符串即;从<b></b>这样的内容并阅读其中的文本。