Creating an XML Document Object

You can create an object representing an XML document—that is, an instance of NSXMLDocument—in one of two general ways. Using NSXML, you can either parse an XML source and create a tree structure representative of the contents, or you can create an XML document programmatically.

Creating a Document Object From Existing XML

The NSXMLDocument class lets you create a document instance from XML markup text in one of several forms: as a string object, as an NSData object, and as a URL-designated file (remote or local). The following initializers of NSXMLDocument (corresponding to these forms) also include parameters for input-handling options and for obtaining information about initialization errors:

Listing 1 shows how you might create an NSXMLDocument instance from an absolute path to a local XML file.

Listing 1  Creating a document from a file URL (local file)

- (void)createXMLDocumentFromFile:(NSString *)file {
    NSXMLDocument *xmlDoc;
    NSError *err=nil;
    NSURL *furl = [NSURL fileURLWithPath:file];
    if (!furl) {
        NSLog(@"Can't create an URL from file %@.", file);
        return;
    }
    xmlDoc = [[NSXMLDocument alloc] initWithContentsOfURL:furl
            options:(NSXMLNodePreserveWhitespace|NSXMLNodePreserveCDATA)
            error:&err];
    if (xmlDoc == nil) {
        xmlDoc = [[NSXMLDocument alloc] initWithContentsOfURL:furl
                    options:NSXMLDocumentTidyXML
                    error:&err];
    }
    if (xmlDoc == nil)  {
        if (err) {
            [self handleError:err];
        }
        return;
    }
 
    if (err) {
        [self handleError:err];
    }
}

If initialization fails, the NSXMLDocument init method directly returns nil and most likely returns by indirection an NSError reporting a parsing or connection error. If failure is due to a parsing error, you can try to recover (as in Listing 1) by initializing the document with the NSXMLDocumentTidyXML option; this option reformats the document prior to parsing to ensure that it is well-formed. However, it does have side effects, such as removing leading and trailing spaces; see the NSXMLDocument reference documentation for details.

If an NSXMLDocument init method indirectly returns an NSError object in its third parameter, you can display an alert dialog to inform the user about the error. However, NSError objects created for parsing errors or warnings might not contain much helpful information. Most NSError objects encapsulate errors or warnings emitted by the parser when documents are not well-formed; these can also be connection errors from attempts to access XML at a remote locations using initWithContentsOfURL:options:error:.

You set initialization options in the second parameter of the three NSXMLDocument initializers discussed above; if you want to specify multiple options, use a bitwise-OR expression. The initialization options cover three categories of input-handling:

These enum constants are defined in NSXMLNodeOptions.h. For specific information about the initialization options, check the reference documentation for NSXMLDocument.

Creating a New XML Document

Sometimes you might want to create an XML document that is entirely new, without there being any original source file or website page. You may want to manipulate all of the nodes in a tree structure—adding, removing, and relocating them—and let NSXML take care of the formatting details when the document is written to a file.

The initWithRootElement: initializer of NSXMLDocument allows you to do this. An NSXMLDocument object has two defining kinds of data: a set of document-global attributes and a root element. Once you have the root element you can construct the rest of the document’s tree representation by adding child nodes of various types to parent nodes at various levels.

Listing 2 shows an example of creating a brand-new XML document object.

Listing 2  Creating an NSXMLDocument instance representing a new document

NSXMLElement *root =
    (NSXMLElement *)[NSXMLNode elementWithName:@"addresses"];
NSXMLDocument *xmlDoc = [[NSXMLDocument alloc] initWithRootElement:root];
[xmlDoc setVersion:@"1.0"];
[xmlDoc setCharacterEncoding:@"UTF-8"];
[root addChild:[NSXMLNode commentWithStringValue:@"Hello world!"]];

This fragment of code uses methods of NSXMLDocument to set the version and encoding attributes of the XML declaration of the document. You could also set the standalone, URI, and MIME-type attributes using the corresponding NSXMLDocument “setter” methods. You may associate a Document Type Definition with the NSXMLDocument object through the setDTD: method. NSXMLDocument also allows you to specify the document’s output format (using setDocumentContentKind:) as HTML, XHTML, text, or (the default) XML. For example, the following lists the different handlings of the <br> element:

Once you create an XML document object and set its attributes, you can start adding content to it—that is, the elements, attributes, and other nodes that make up an XML document—through the appropriate methods of NSXMLElement and NSXMLNode.

If the XML document has a schema associated with it—defined either with a DTD or XML Schema —you might want to validate the document periodically. To validate a document, send the validateAndReturnError: message to the NSXMLDocument object. If the operation is not valid, the method returns NO; the reasons for invalidity are returned by indirection in the method’s NSError parameter.