npgall
npgall

Reputation: 3028

Pretty print XML from NSString in Objective-C

I have an XML document in an NSString object in Objective-C.

The XML is obtained from a web service, and it doesn't have any formatting, line breaks or indentation.

Can anyone tell me the easiest way to produce a new NSString object, which has the XML formatted nicely, with each element on a new line with proper indentation etc?

Upvotes: 3

Views: 2590

Answers (2)

enreas
enreas

Reputation: 11262

In case you don't want to include GData in your project, use this method:

+ (NSString *)prettyPrintXML:(NSString *)rawXML {
    const char *utf8Str = [rawXML UTF8String];
    xmlDocPtr doc = xmlReadMemory(utf8Str, (int)strlen(utf8Str), NULL, NULL, XML_PARSE_NOCDATA | XML_PARSE_NOBLANKS);
    xmlNodePtr root = xmlDocGetRootElement(doc);
    xmlNodePtr xmlNode = xmlCopyNode(root, 1);
    xmlFreeDoc(doc);

    NSString *str = nil;

    xmlBufferPtr buff = xmlBufferCreate();
    doc = NULL;
    int level = 0;
    int format = 1;

    int result = xmlNodeDump(buff, doc, xmlNode, level, format);

    if (result > -1) {
        str = [[NSString alloc] initWithBytes:(xmlBufferContent(buff))
                                       length:(NSUInteger)(xmlBufferLength(buff))
                                     encoding:NSUTF8StringEncoding];
    }
    xmlBufferFree(buff);

    NSCharacterSet *ws = [NSCharacterSet whitespaceAndNewlineCharacterSet];
    NSString *trimmed = [str stringByTrimmingCharactersInSet:ws];
    return trimmed;
}

It's adaptated from GData's init and XMLString methods, stripping error checks to keep it short. Please remember to include them as you need.

This way you just have to include libxml2 to your search path (that's step 2 in previous answer) and #import <libxml/tree.h> to format XML in Objective-C.

Upvotes: 8

npgall
npgall

Reputation: 3028

Okay so I solved this myself.

This uses Google's GData XML parsing wrapper around the built-in /usr/include/libxml2 XML library, to convert an NSString containing unformatted XML, into another NSString which is nicely formatted, with indentation and line breaks.

Note this is based on Xcode 5, and the target is iOS 7; although it might work for other targets too.


Step 1. Copy GData classes (source) into the project

Copy 2 source files, GDataXMLNode.h and GDataXMLNode.m, from the GData library directly into the project.


Step 2. Add libxml2 to the search path

In Project -> Build Settings -> Search Paths -> Header Search Paths, add path: /usr/include/libxml2

In Project -> Build Settings -> Linking -> Other Linker Flags, add flag: -lxml2


Step 3. If your app uses ARC, disable ARC for the GData class

In Targets -> Build Phases -> Compile Sources -> GDataXMLNode.m, add Compiler Flag: -fno-objc-arc

At this point, make sure your project builds. If it does, GData is configured correctly.


Step 4. Edit GDataXMLNode.m to make it pretty-print XML by default

Open GDataXMLNode.m, and find method - (NSString *)XMLString

Change: int format = 0;

To: int format = 1;


Step 5. Add the following method anywhere in your project

#import "GDataXMLNode.h"

+ (NSString *)prettyPrintXML:(NSString *)rawXML {
    NSError *error;
    GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithXMLString:rawXML options:0 error:&error];
    return error ? rawXML : doc.rootElement.XMLString;
}

That's it, this method will convert a raw XML string into a nicely formatted string.

Upvotes: 8

Related Questions