سؤال

I've been trying to figure this out for a little while, but can't work it out. Hopefully someone on here will have an idea.

I have some XML data that i am parsing, It looks like:

    <Name>MAC 101</Name>
    <Modes>
        <Mode>
            <Name>Basic RGB</Name>
            <ChannelCount>8</ChannelCount>
        </Mode>
        <Mode>
            <Name>Raw RGB</Name>
            <ChannelCount>12</ChannelCount>
        </Mode>
    </Modes>

What I am doing is saving the info to an SQLite database, However i need to combine some info into 1 string first. I need the string to look like: (with the line break)

8 Basic RGB
12 Raw RGB

However sometimes there will be multiple "Modes" this example only has 2, sometimes it could be a dozen or more.

The current code i'm using is NSXMLParser:

-(void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if (isStatus) {
    if ([elementName isEqualToString:@"Name"]) {
        CurrentFixture.Title = currentNodeContent;
        NSLog(@"Name: %@",currentNodeContent);
    }
    if ([elementName isEqualToString:@"Name"]) {
        CurrentFixture.ModeName = currentNodeContent;
        NSLog(@"Mode Name: %@",currentNodeContent);
    }
    if ([elementName isEqualToString:@"ChannelCount"]) {
        CurrentFixture.ChannelCount = currentNodeContent;
        NSLog(@"Channel Count: %@",currentNodeContent);
    }
}
 if ([elementName isEqualToString:@"Fixture"]) {
    NSLog(@"Do something with data.");
    [self.data addObject:CurrentFixture];
    NSLog(@"Data: %@",);
    CurrentFixture = nil;
    currentNodeContent = nil;
    }
}

The Mode name will be changing tags so it doesn't get confused with the actual name, But at the moment I just need to get something working. Any advise or guidance would be much appreciated. Thanks Andrew

هل كانت مفيدة؟

المحلول

You need

  • an array to keep track of all of your modes, e.g. modesArray;

  • a dictionary of object to keep track of you're modes' ChannelCount and Name, e.g. modeDictionary; and

  • and some BOOL variable so you know if you're parsing your array of modes or not (most importantly, so you can distinguish between Name in a Mode and the higher-level Name, e.g. parsingModes.

You can then,

  • When you start a Modes, initialize your array;

  • When you start a Mode, initialize the dictionary;

  • When you complete a Name or ChannelCount, update the mode dictionary;

  • When you complete a Mode, you can concatenate these two values into a single string, and add that string to your array;

  • When you complete the Modes, you can join all of those strings in the Mode array with a newline.

Thus yielding something like:

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
    if ([elementName isEqualToString:@"Fixture"])
    {
        currentFixture = [[Fixture alloc] init];
    }
    else if ([elementName isEqualToString:@"Modes"])
    {
        modesArray = [NSMutableArray array];
        parsingModes = YES;
    }
    else if ([elementName isEqualToString:@"Mode"])
    {
        modeDictionary = [NSMutableDictionary dictionary];
    }
    else
    {
        currentNodeContent = [NSMutableString string];
    }
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
    [currentNodeContent appendString:string];
}

-(void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
    if (parsingModes)
    {
        if ([elementName isEqualToString:@"Name"]) {
            modeDictionary[@"Name"] = currentNodeContent;
        }
        else if ([elementName isEqualToString:@"ChannelCount"]) {
            modeDictionary[@"ChannelCount"] = currentNodeContent;
        }
        else if ([elementName isEqualToString:@"Mode"]) {
            [modesArray addObject:[NSString stringWithFormat:@"%@ %@", modeDictionary[@"ChannelCount"], modeDictionary[@"Name"]]];
            modeDictionary = nil;
        }
        else if ([elementName isEqualToString:@"Modes"]) {
            currentFixture.longStringWithModes = [modesArray componentsJoinedByString:@"\n"];
            modesArray = nil;
            parsingModes = NO;
        }
    }
    else
    {
        if ([elementName isEqualToString:@"Name"]) {
            currentFixture.title = currentNodeContent;
        }
    }

    // carry on with your other elements

    currentNodeContent = nil;
}

(Note I shifted to camelCase.)

Having shown you how to do this, I'd advise against it. It's better for the database to keep the data in separate fields. This concatenating everything into a single string might be something you do in the UI, but the database should probably reflect the underlying data structure. Having said that, since you have multiple Mode entries for each fixture, that means that you'd probably have a separate table for those.

نصائح أخرى

You would want a function once all of the parsing is done. It doesn't look like you gave us the whole XML file, but I'm assuming that your outer tag is <Fixtures> and your inner tags are <Fixture>. Going off that assumption, you can add a check in parser:didEndElement:

-(void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
    //...

    if ([elementName isEqualToString:@"Fixtures"]) {
        [self saveModesToDatabase];
    }
}

-(void) saveModesToDatabase {
    NSString* allModes = @"";
    for (Fixture* aFixture in self.data) {
        NSString* modeString = [aFixture.ChannelCount stringByAppendingFormat:@" %@", aFixture.Title];

        // Don't add a line break if it's the last object
        if (aFixture == [self.data lastObject])
            allModes = [allModes stringByAppendingFormat:@"%@", modeString];
        else
            allModes = [allModes stringByAppendingFormat:@"%@\n", modeString];
    }

    // Save allModes to database
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top