了解iOS中的NSXMLParser [英] Learn about the NSXMLParser in iOS

查看:101
本文介绍了了解iOS中的NSXMLParser的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



My Parser类看起来像:

  #import< Foundation / Foundation.h> 

@interface解析器:NSXMLParser

@property(非原子,强)NSString * rowElementName; //这是标识XML
@property(非原子,强)NSArray * attributeNames中的新数据行的元素名称; //这是我们可能想要为该元素名称检索的属性数组
@property(nonatomic,strong)NSArray * elementNames; //这是我们要检索值的子元素名称列表

@property(nonatomic,strong)NSMutableArray * items; //解析后,这是解析项目数组

@end

  #importParser.h

@interface Parser()< NSXMLParserDelegate>

@property(nonatomic,strong)NSMutableDictionary * item; //在解析时,这是当前正在解析的项目
@property(nonatomic,strong)NSMutableString * elementValue; //这是被解析的项目中的元素

@end

@implementation解析器

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

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

返回自我;
}

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

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

返回自我;
}

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

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

返回自我;
}

#pragma mark - NSXMLParserDelegate方法

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

if(!self.rowElementName)
NSLog(@%s警告:无法指定行标识符元素名称,__ FUNCTION__);
}

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

for(self.attributeNames中的NSString * attributeName)
{
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)解析器:(NSXMLParser *)解析器foundCharacters:(NSString *)string
{
if(self.elementValue) )
{
[self.elementValue appendString:string];
}
}

- (void)解析器:(NSXMLParser *)解析器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

已创建通过。但是,在这个答案的最后,如果您只是试图搂着 NSXMLParser ,我会包含对Apple解析文档的一些引用。



注释地图



在iPhone上映射应用程序的常见模型是不在地图视图本身上显示包含丰富内容的popover,但是相反,由于iPhone的房地产有限,只显示标准标注,但设置 rightCalloutAccessoryView 作为披露指标,如果你点击它,将会发出信号带有细节的下一个视图。因此,通过使用 UIMapViewDelegate 方法,您可以使用 mapView:viewForAnnotation:表示:

   - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id< MKAnnotation>)注释
{
MKAnnotationView * annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@loc];
annotationView.canShowCallout = YES;
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];

返回annotationView;
}

这会产生以下用户界面:





然后你可以有一个 mapView:annotationView:calloutAccessoryControlTapped:就像这样:

   - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control 
{
[self performSegueWithIdentifier:@DetailsIphonesender:view];
}

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





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





但是这里你可以有 mapView:annotationView:calloutAccessoryControlTapped:实际上生成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
allowedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
}

产生:





顺便说一句,这个大致近似于iPad Maps应用程序的工作方式(当您点击某个图钉时,它会显示带有信息按钮的标注),如果您再单击信息按钮,它会向您显示带有详细信息的弹出窗口。



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

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

返回annotationView;
}

但是你必须回复 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
allowedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
}

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



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






解析引用:





地图视图标注参考:




I learn about current NSXMLParser. I read many tutorials but none could tell me exactly how it works. there is a tutorial on StackOverflow? My problem is this KML read structur in my app and display with MKMapView

My Parser class looks like:

#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

and

#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

created by rob

my XML-file:

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

My goal is to get all the Informations in the <description> tag and displayed it like it Google-Maps do

not exactly but Similar.

but first i need to know how i can work with the Parser

Best regards CTS

解决方案

There were two fundamentally different components to this question, parsing and annotating maps. I'll focus on the map annotation here, as I think I covered the parsing questions here: Try to load a created Map in MKMapView. At the end of this answer, though, I include some references to Apple's parsing documentation if you're just trying to get your arms around NSXMLParser.

Annotating maps

The common model in mapping apps on the iPhone is to not show a popover with rich content on the maps view itself, but rather, due to the iPhone's limited real estate, to just show the standard callout, but set the rightCalloutAccessoryView to be a disclosure indicator, which, if you tap on it, will segue to that next view with the details. Thus, by using UIMapViewDelegate methods, you can have a mapView:viewForAnnotation: that says:

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

This yields the following user interface:

You can then have a mapView:annotationView:calloutAccessoryControlTapped: like so:

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

You can use that to go to your details screen. (I'm just doing a modal segue to a view controller with a web view, passing the annotation in the prepareForSegue, and the viewDidLoad is grabbing the html, etc. The details here are unremarkable. I assume you can transition to your own details screen and design something prettier than this quick and dirty web view ... I'm just demonstrating that we can grab the HTML for a placemark out of the KML file):

So, while the iPhone really shouldn't be using popovers on the map itself, on the iPad, you can use them. You can create the rightCalloutAccessoryView in a similar manner (though maybe use the "info" button rather than the detail disclosure):

But here you can have mapView:annotationView:calloutAccessoryControlTapped: actually generate the popover rather than doing a modal transition:

- (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];
}

which yields:

By the way, this roughly approximates how the iPad Maps app does it (when you click on a pin, it shows you a callout with an "info" button), which if you then click on the info button, it shows you the popover with details.

Alternatively, you could have the click on the pin take you right to your popover, bypassing the intervening callout. To do so, you first, though, have to disable the callout on the annotation view, itself:

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

    return annotationView;
}

But you then have to respond to 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];
}

Theoretically, you could do something like this on the iPhone, but since you can't use UIPopoverController, you'd have to use some third-party popover (or write your own). I've heard some people allege that Apple has rejected iPhone apps for using popover views, though I can neither confirm that, nor say whether that's a hard and fast rule. I just know that the Apple and Google iPhone mapping apps do not use large popover views on the iPhone maps apps (Apple segues to another view, Google has it appear at the bottom of the screen). And if you think about it, if the pin is right in the center and you tried to generate a large popover pointing to that pin, it might get cramped.

Anyway, those are the options for using rightCalloutAccessoryView settings and/or disabling canShowCallout and showing the popover directly.


Parsing references:

Map view callout reference:

这篇关于了解iOS中的NSXMLParser的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆