views:

52

answers:

1

I'm in the making of an application where I'm using TouchXML to parse an XML containing airport flight information.

The XML looks like this:

<?xml version="1.0" encoding="iso-8859-1"?>
<airport xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://flydata.avinor.no/XmlFeed.xsd" name="OSL">
    <flights lastUpdate="2010-10-03T12:29:43">
        <flight uniqueID="1273306">
            <airline>DY</airline>
            <flight_id>DY246</flight_id>
            <dom_int>D</dom_int>
            <schedule_time>2010-10-03T10:45:00</schedule_time>
            <arr_dep>D</arr_dep>
            <airport>TOS</airport>
            <check_in>D</check_in>
            <gate>18</gate>
            <status code="D" time="2010-10-03T10:42:00"/>
        </flight>
        <flight uniqueID="1273799">
            <airline>SK</airline>
            <flight_id>SK263</flight_id>
            <dom_int>D</dom_int>
            <schedule_time>2010-10-03T10:50:00</schedule_time>
            <arr_dep>D</arr_dep>
            <airport>BGO</airport>
            <check_in>EF</check_in>
            <gate>23</gate>
        </flight>
    </flights>
</airport>

The TouchXML documentation tells me how to fetch attributes, which works for flights's lastUpdate attribute, but not for status's code and time attribute.

In addition, not all flight XML entries contain the status element, but I'm doing a check for this.

Currently, the code I have is the following:

-(void)grabXML {
    flightEntries = [[NSMutableArray alloc] init];

    NSURL *url = [NSURL URLWithString:@"http://flydata.avinor.no/XmlFeed.asp?TimeFrom=0&amp;TimeTo=2&amp;airport=OSL&amp;direction=D"];

    CXMLDocument *xmlParser = [[[CXMLDocument alloc] initWithContentsOfURL:url options:0 error:nil] autorelease];

    NSArray *resultNodes = NULL;

    resultNodes = [xmlParser nodesForXPath:@"//flight" error:nil];

    for (CXMLElement *resultElement in resultNodes) {
        NSMutableDictionary *flightItem = [[NSMutableDictionary alloc] init];

        int counter;

        for (counter = 0; counter < [resultElement childCount]; counter++) {
            [flightItem setObject:[[resultElement childAtIndex:counter] stringValue] forKey:[[resultElement childAtIndex:counter] name]];

            // Check if the node has the <status> element
            if ([[[resultElement childAtIndex:counter] name] isEqualToString:@"status"]) {
                // Fetch the code and time attribute here
            }
        }

        // This gives me <flight uniqueID="*">
        [flightItem setObject:[[resultElement attributeForName:@"uniqueID"] stringValue] forKey:@"uniqueID"];

        [flightEntries addObject:[flightItem copy]];
    }
}

The documentation does not tell how to parse multiple attributes, so I was hoping someone had a clue on how to do it?

A: 

First off, I have to say that your XML will be difficult to work with because you are trying to use a specific tag for each item in a list. For example:

            <airline>DY</airline>
            <flight_id>DY246</flight_id>
            <dom_int>D</dom_int>
            <schedule_time>2010-10-03T10:45:00</schedule_time>
            <arr_dep>D</arr_dep>
            <airport>TOS</airport>
            <check_in>D</check_in>
            <gate>18</gate>

the tags named , don't make sense as XML is intended to describe your data, not define it. If you have an entity called an item, you should probably just call it item and make the XML look like this:

 <level1_items>
    <level1_item>
      <item index="1">text</item_1>
      <item index="2">text</item_2>
    </level1_item>
    <level1_item>
      <item index="1">some text</item_1>
      <item index="2">some more text</item_2>
  </level1_items>

Where each item has an index. For that matter, you could just load the document in your TouchXML CXMLDocument and grab the nodes you need with XPath and assume they're in the correct order ignoring the index= parameter I specified.

The next issue is that converting XML to an NSDictioanry or NSArray of dictionaries is a pretty involved task and what you gain isn't worth the effort. Just load your XML into a CXMLDocument and then start obtaining nodes using XPath. Something like this:

CXMLDocument *doc = [[CXMLDocument alloc] initWithXMLString:xmlString options:0 error:nil];

// Returns all 'level1_item' nodes in an array    
NSArray *nodes = [[doc rootElement] nodesForXPath:@"//response/level1_items/level1_item" error:nil];

for (CXMLNode *itemNode in nodes)
{
    for (CXMLNode *childNode in [itemNode children])
    {
        NSString *nodeName = [childNode name]; // should contain item_1 in first iteration
        NSString *nodeValue = [childNode stringValue]; // should contain 'text' in first iteration
        // Do something with the node data.

    }
}

suggest trying to use the XML this way and then come back here and ask specific questions if you have problems.

hope that helps.

PK

Pavan
Thank you PK. My code was based on a tutorial which originally parsed a RSS feed. My problem is that I don't have the control of the XML. I can agree with you on the difficulty of the XML, and that's why I came to StackOverflow for help.
rebellion