首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >基于libxml2 XPathQuery的XML DOM解析

基于libxml2 XPathQuery的XML DOM解析
EN

Stack Overflow用户
提问于 2013-11-22 17:52:54
回答 1查看 211关注 0票数 0

我试图解析以下XML文件:

代码语言:javascript
复制
<MesPar DH="HBCHa" StrNr="2416" Typ="10" Var="10">
    <Name>Aabach - Hitzkirch</Name>
    <Datum>11.11.2013</Datum>
    <Zeit>18:00</Zeit>
    <Wert>2.02</Wert>
    <Wert dt="-24h">1.93</Wert>
</MesPar>

<MesPar DH="HBCHa" StrNr="2312" Typ="02" Var="00">
    <Name>Aach - Salmsach</Name>
    <Datum>11.11.2013</Datum>
    <Zeit>18:00</Zeit>
    <Wert>406.47</Wert>
    <Wert dt="-24h">406.64</Wert>
</MesPar>

如果属性"StrNr“等于"2416”,我将读取元素值。我的代码是:

代码语言:javascript
复制
NSURL *url = [NSURL URLWithString:@"http://www.hydrodaten.admin.ch/lhg/SMS.xml"];
NSData *webData = [NSData dataWithContentsOfURL:url options:NSUTF8StringEncoding error:nil];
TFHpple *parser = [TFHpple hppleWithData:webData isXML:YES];
NSString *xPathQuery = @"//AKT_Data/MesPar";
NSArray *arrayPaser= [parser searchWithXPathQuery:xPathQuery];

NSMutableArray *arrayName = [[NSMutableArray alloc] initWithCapacity:0];
NSMutableArray *arrayDatum = [[NSMutableArray alloc] initWithCapacity:0];
NSMutableArray *arrayWertDt24h = [[NSMutableArray alloc] initWithCapacity:0];


for (TFHppleElement *element in arrayPaser) {
    if ([[element firstChild] content]!=nil) {
        NSDictionary *attribute=[element attributes];

        NSString *string= [NSString stringWithFormat:@"%@",[attribute valueForKey:@"StrNr"]];

        if ([string isEqualToString:@"2416"]) {

            arrayName addObject:[element ??????];
            arrayDatum addObject:[element ?????];
            arrayWertDt24h addObject:[element ????];
        }

我不知道我是怎么得到元素的值的?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-11-26 02:34:04

我有一个解决方案,涉及使用内置的NSXMLParser和几个NSXMLParserDelegate方法。

让我们来创建第一个子类NSObject并创建一个解析器类。下面是.h:

代码语言:javascript
复制
#import <Foundation/Foundation.h>

@interface XMLParser : NSObject

- (id)initWithData:(NSData *)data;
- (BOOL)parse;

@end

在这里,您可以看到,我们将为这个对象提供您想要解析的数据,然后我们可以告诉它解析。解析方法只是NSXMLParser解析方法的包装器,稍后您将看到它。

类扩展是我们将添加用于管理我们正在解析的数据的私有属性的地方。情况如下:

代码语言:javascript
复制
@interface XMLParser ()
<NSXMLParserDelegate>

@property (nonatomic, strong) NSData *data;
@property (nonatomic, strong) NSXMLParser *parser;
@property (nonatomic, strong) NSMutableDictionary *objectDict;
@property (nonatomic, strong) NSMutableString *elementDataString;
@property (nonatomic, strong) NSMutableDictionary *wertTwo;
@property (nonatomic, assign, getter = isParsingWertTwo) BOOL parsingWertTwo;

@end

dataparser属性是不言自明的。我们将使用objectDict属性来存储您希望从这个XML解析的数据。elementDataString将保存解析器在元素标记之间找到的字符。我们有一个wertTwo属性和一个标志来指示解析第二个Wert元素的时间。这样我们就可以确保从第二个Wert元素中获取属性。

执行工作的开始如下:

代码语言:javascript
复制
@implementation XMLParser

- (id)initWithData:(NSData *)data
{
    self = [super init];
    if (self) {
        self.data = data;
        self.parser = [[NSXMLParser alloc] initWithData:data];
        self.parser.delegate = self;
        self.objectDict = [@{} mutableCopy];
        self.wertTwo = [@{} mutableCopy];
    }
    return self;
}

- (BOOL)parse
{
    return [self.parser parse];
}

正如您从初始化器中看到的,我们设置了我们需要的对象以及数据和解析器来执行实际的解析。我提到的解析方法简单地包装了NSXMLParser类的解析方法。它实际上返回一个BOOL,这就是为什么我选择在这里返回它。我们将self设置为解析器的委托,因此我们必须在委托协议中实现一些方法,以获得必要的数据。委托方法如下:

代码语言:javascript
复制
#pragma mark - NSXMLParserDelegate

- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
  namespaceURI:(NSString *)namespaceURI
 qualifiedName:(NSString *)qName
    attributes:(NSDictionary *)attributeDict
{
    if ([elementName isEqualToString:@"MesPar"]) {

        // Get the value from the attribute dict of the MesPar element
        NSString *value = attributeDict[@"StrNr"];

        // Compare whether the value is equal to the desired value
        if ([value isEqualToString:@"2416"]) {

            // if the value is equal, add the attribute dict to the object dict
            [self.objectDict addEntriesFromDictionary:attributeDict];

            return;
        }
    }

    // If the element is Wert AND there is an attribute named dt we know this is the second Wert element
    if ([elementName isEqualToString:@"Wert"] && attributeDict[@"dt"]) {

        // add the attribute element to the wertTwo dict
        [self.wertTwo addEntriesFromDictionary:attributeDict];

        // Set the parsing flag to YES so we know where we are in the delegate methods
        self.parsingWertTwo = YES;

        return;
    }
}

- (void)parser:(NSXMLParser *)parser
 didEndElement:(NSString *)elementName
  namespaceURI:(NSString *)namespaceURI
 qualifiedName:(NSString *)qName
{
    // if this is the Name element, set the element data in the object dict
    if ([elementName isEqualToString:@"Name"]) {
        [self.objectDict setObject:[self.elementDataString copy] forKey:@"name"];

        // set the data to nil since it will be reset by a delegate method for the next element
        self.elementDataString = nil;

        return;
    }

    if ([elementName isEqualToString:@"Datum"]) {
        [self.objectDict setObject:[self.elementDataString copy] forKey:@"datum"];

        // set the data to nil since it will be reset by a delegate method for the next element
        self.elementDataString = nil;

        return;
    }

    if ([elementName isEqualToString:@"Zeit"]) {
        [self.objectDict setObject:[self.elementDataString copy] forKey:@"zeit"];

        // set the data to nil since it will be reset by a delegate method for the next element
        self.elementDataString = nil;

        return;
    }


    if ([elementName isEqualToString:@"Wert"]) {

        // Checks to see if this is the Wert element AND that we are parsing the second element
        if (self.isParsingWertTwo) {
            [self.wertTwo setObject:[self.elementDataString copy] forKey:@"wertTwoString"];

            // set the wertTwo dict for the key wertTwo in the object dict
            // this allows us to pull out this info for the key wertTwo and includes the attribute of dt along with the elementDataString
            [self.objectDict setObject:[self.wertTwo copy] forKey:@"wertTwo"];

            // set the data to nil since it will be reset by a delegate method for the next element
            self.elementDataString = nil;

            return;
        }
        else{
            [self.objectDict setObject:[self.elementDataString copy] forKey:@"wertOne"];

            // set the data to nil since it will be reset by a delegate method for the next element
            self.elementDataString = nil;

            return;
        }
    }
}

- (void)parserDidEndDocument:(NSXMLParser *)parser
{
    // You do not have to implement this but if you'd like here you can access `self.objectDict` which should have a representation of your XML you're looking to parse
}


- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
    // Append the foundCharacters (in between the element tags) to the data string
    [self.elementDataString appendString:string];
}

代码是对实际发生的事情进行注释的,但简而言之,解析器在此实例中通知委托时,当某些事情发生时,例如当它遇到一个元素时,或者当它正在查找字符时,解析器就会通知它。需要记住的一件事是,elementDataString属性需要被延迟加载,我们这样做:

代码语言:javascript
复制
// lazy loads the elementDataString if it is nil
// it will be set to nil after each time it is set in a dict
// this is why we copy it when we add it to the dict
- (NSMutableString *)elementDataString
{
    if (!_elementDataString) {
        _elementDataString = [NSMutableString string];
    }
    return _elementDataString;
}

有几件事我还没有解决,比如解析中的错误或您可能感兴趣的其他委托方法。这是一个特殊的解决方案,它使用内置的类,而不是依赖第三方库。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20151375

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档