Search code examples
iphoneobjective-cxmlreaderxmlstreamreader

XMLStreamReader for Objective C iPhone?


I am using XMLWriter for generating the xml. Now I want to read this xml with some Reader library/framework. Is there any complementary framework/library available for this.

I am currently looking to use TouchXML library to read this, but its not working in the expected way as it does not support stream reading.

I want do something like:

XmlReader pReader = XmlTextReader.Create(pPath);

    while (pReader.Read()){

        switch (pReader.LocalName){
            case EXPEL_DEVICES:
            {
                //if ((pImportFlags & (int)ExportClass.Devices) != 0)
                //{
                for (pReader.ReadToFollowing(LOCAL_NAME, NAMESPACE_EXPORT);
                     !pReader.EOF && pReader.LocalName == @"NAME"; )
                {
                    if (!pReader.ReadToFollowing(DEVICE_ID, NAMESPACE_EXPORT))
                        throw new AException(DEVICE_ID);
                    NSString *value = pReader.ReadElementContentAsString();
                }
            }
                break;
        }
    }

Solution

  • After loosing my own reputation worth 50, I finally used libxml2 and made my XMLStreamReader class as following, I wish I could have found this earlier :P. Please note that for using this we need include libxml2.dylib inot our frameworks and in the build settings do add -lxml2 into other linker flags and in header search paths add /usr/include/libxml2

    The header file:

    #import <Foundation/Foundation.h>
    #import <libxml/xmlreader.h>
    
    @interface XMLStreamReader : NSObject {
        xmlTextReaderPtr xmlReader;
    }
    
    @property (nonatomic, readonly, assign) BOOL eof;
    @property (nonatomic, readonly, retain) NSString *localName;
    @property (nonatomic, readonly, assign) xmlElementType nodeType;
    @property (nonatomic, readonly, assign) BOOL read;
    @property (nonatomic, readonly, assign) BOOL readElementContentAsBoolean;
    @property (nonatomic, readonly, retain) NSString *readElementContentAsString;
    
    - (void) close;
    - (id) getAttribute:(NSString *) paramName;
    - (id) initWithPath:(NSString *) path;
    @end
    

    The implementation file:

    #import "XMLStreamReader.h"
    
    @implementation XMLStreamReader
    
    @dynamic eof;
    @dynamic localName;
    @dynamic nodeType;
    @dynamic read;
    @dynamic readElementContentAsBoolean;
    @dynamic readElementContentAsString;
    
    - (void) dealloc{
        xmlFreeTextReader(xmlReader);
        [super dealloc];
    }
    
    /**
     * xmlTextReaderClose:
     * @reader:  the xmlTextReaderPtr used
     *
     * This method releases any resources allocated by the current instance
     * changes the state to Closed and close any underlying input.
     *
     * Returns 0 or -1 in case of error
     */
    - (void) close{
        xmlTextReaderClose(xmlReader);
    }
    
    /**
     * @reader:  the xmlTextReaderPtr used
     * @name: the qualified name of the attribute.
     *
     * Provides the value of the attribute with the specified qualified name.
     *
     * Returns a string containing the value of the specified attribute, or NULL
     *    in case of error. The string must be deallocated by the caller.
     */
    - (id) getAttribute:(NSString *) paramName{
        xmlChar *attribute = xmlTextReaderGetAttribute(xmlReader, (xmlChar *)[paramName UTF8String]);
    
        if(attribute != NULL){
            NSString *rtString = [NSString stringWithUTF8String:(const char *)attribute];
            free(attribute);
            return rtString;
        }
        return NULL;
    }
    
    /**
     * Checks if, the reader has reached to the end of file
     * 'EOF' is not used as it is already defined in stdio.h
     * as '#define  EOF (-1)'
     */
    - (BOOL) eof{
        return xmlTextReaderReadState(xmlReader) == XML_TEXTREADER_MODE_EOF;
    }
    
    /**
     * Initializing the xml stream reader with some uri
     * or local path.
     */
    - (id) initWithPath:(NSString *) path{
        if(self = [super init]){
            xmlReader = xmlNewTextReaderFilename([path UTF8String]);
            if(xmlReader == NULL)
                return nil;
        }
        return self;
    }
    
    /**
     * @reader:  the xmlTextReaderPtr used
     *
     * The local name of the node.
     *
     * Returns the local name or NULL if not available,
     *   if non NULL it need to be freed by the caller.
     */
    - (NSString *) localName{
        xmlChar *lclName = xmlTextReaderLocalName(xmlReader);
    
        if(lclName != NULL){
            NSString *rtString = [NSString stringWithUTF8String:(const char *)lclName];
            free(lclName);
            return rtString;
        }
        return NULL;
    }
    
    - (xmlElementType) nodeType{
        return xmlTextReaderNodeType(xmlReader);
    }
    
    /**
     * @reader:  the xmlTextReaderPtr used
     *
     *  Moves the position of the current instance to the next node in
     *  the stream, exposing its properties.
     *
     *  Returns 1 if the node was read successfully, 0 if there is no more
     *          nodes to read, or -1 in case of error
     */
    - (BOOL) read{
        return xmlTextReaderRead(xmlReader);
    }
    
    /**
     * @reader:  the xmlTextReaderPtr used
     *
     * Reads the contents of an element or a text node as a Boolean.
     *
     * Returns a string containing the contents of the Element or Text node,
     *         or NULL if the reader is positioned on any other type of node.
     *         The string must be deallocated by the caller.
     */
    - (void) readElementContentAsBoolean{
        return [[self readElementContentAsString] boolValue];
    }
    
    /**
     * @reader:  the xmlTextReaderPtr used
     *
     * Reads the contents of an element or a text node as a string.
     *
     * Returns a string containing the contents of the Element or Text node,
     *         or NULL if the reader is positioned on any other type of node.
     *         The string must be deallocated by the caller.
     */
    - (NSString *) readElementContentAsString{
        xmlChar *content = xmlTextReaderReadString(xmlReader);
    
        if(content != NULL){
            NSString *rtString = [NSString stringWithUTF8String:(const char *)content];
            free(content);
            return rtString;
        }
        return NULL;
    }
    
    /**
     * @reader:  the xmlTextReaderPtr used
     * @localName:  the local name of the attribute.
     * @namespaceURI:  the namespace URI of the attribute.
     *
     * Moves the position of the current instance to the attribute with the
     * specified local name and namespace URI.
     *
     * Returns 1 in case of success, -1 in case of error, 0 if not found
     */
    - (int) readToFollowing:(NSString *) localname namespace:(NSString *) namespaceURI{
        return xmlTextReaderMoveToAttributeNs(xmlReader, (xmlChar *)[localname UTF8String], (xmlChar *)[namespaceURI UTF8String]);
    }
    
    @end