了解iOS中的NSXMLParser

CTS*_*idt 6 nsxmlparser mapkit mkannotationview ios

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

我的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
Run Code Online (Sandbox Code Playgroud)

#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
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

我的目标是获取<description>标签中的所有信息并将其显示为Google-Maps在此输入图像描述

不完全但是相似.

但首先我需要知道如何与Parser一起工作

最好的问候CTS

Rob*_*Rob 16

这个问题有两个根本不同的组件,解析和注释地图.我将在这里专注于地图注释,因为我认为我在这里介绍了解析问题:尝试在MKMapView中加载创建的地图.但是,在这个答案的最后,如果您只是试图让自己动手,我会在Apple的解析文档中加入一些参考NSXMLParser.

注释地图

在iPhone上映射应用程序的常见模式是不在地图视图本身上显示具有丰富内容的popover,而是由于iPhone的有限空间,仅显示标准标注,但将其设置rightCalloutAccessoryView为披露指示,如果你点击它,将切换到详细信息的下一个视图.因此,通过使用UIMapViewDelegate方法,您可以mapView:viewForAnnotation:说:

- (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;
}
Run Code Online (Sandbox Code Playgroud)

这会产生以下用户界面:

正确的标注配件

你可以mapView:annotationView:calloutAccessoryControlTapped:这样:

- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
    [self performSegueWithIdentifier:@"DetailsIphone" sender:view];
}
Run Code Online (Sandbox Code Playgroud)

您可以使用它来转到您的详细信息屏幕.(我只是对带有Web视图的视图控制器进行模态转换,在其中传递注释prepareForSegue,并且viewDidLoad正在抓取html等.此处的详细信息不起眼.我假设您可以转换到您自己的详细信息屏幕,设计比这个快速而肮脏的Web视图更漂亮的东西......我只是在演示我们可以从KML文件中获取地标的HTML):

iPhone详情屏幕

因此,虽然iPhone真的不应该在地图上使用弹出窗口,但在iPad上,你可以使用它们.您可以rightCalloutAccessoryView以类似的方式创建(虽然可能使用"信息"按钮而不是详细信息披露):

iPad右侧标注配件

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

- (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];
}
Run Code Online (Sandbox Code Playgroud)

产量:

iPad popover

顺便说一下,这大致近似了iPad Maps应用程序的工作方式(当你点击一个图钉时,它会显示一个带有"信息"按钮的标注),如果你点击信息按钮,它会显示你的弹出窗口有详细信息.

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

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
    MKAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"loc"];
    annotationView.canShowCallout = NO;

    return annotationView;
}
Run Code Online (Sandbox Code Playgroud)

但是你必须回复mapView:didSelectAnnotationView::

- (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];
}
Run Code Online (Sandbox Code Playgroud)

从理论上讲,你可以在iPhone上做这样的事情,但由于你不能使用UIPopoverController,你必须使用一些第三方popover(或自己编写).我听说有些人声称Apple拒绝使用popover视图的iPhone应用程序,虽然我既不能确认,也不能说这是否是一个硬性规则.我只知道Apple和谷歌iPhone地图应用程序不会在iPhone地图应用程序上使用大型弹出窗口视图(Apple转向另一种视图,Google将其显示在屏幕底部).如果你考虑一下,如果针脚在中间位置并且你试图生成一个指向该针脚的大型弹出窗口,它可能会变得狭窄.

无论如何,这些是使用rightCalloutAccessoryView设置和/或禁用canShowCallout和直接显示弹出窗口的选项.


解析参考文献:

地图视图标注参考: