Small set of classes to simplify XML/HTML generation in Cocoa apps.
Clone or download
Pull request Compare This branch is 208 commits behind karelia:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.
KSWriter @ 3de4c7d



KSHTMLWriter is a set of classes for generating HTML and XML markup programmatically. It is quite easy in Cocoa to start producing XML by using +stringWithFormat: etc. but this can quickly grow to become unwieldy. KSHTMLWriter simplifies the task considerably, while offering plenty of flexibility.

Another benefit is that markup is generated in a stream-like fashion, potentially cutting down on memory overhead. You can think of it as the opposite of NSXMLParser etc.

KSHTMLWriter instances are safe to use on any thread, but should only be accessed by a single thread at a time.

Adding KSHTMLWriter to your project

The simplest way to add KSHTMLWriter to your project is to directly add the source files to your project. For XML generation, the following are required:

  • KSWriter/*
  • KSXMLWriter.h
  • KSXMLWriter.m
  • KSElementInfo.h
  • KSElementInfo.m

For HTML generation, add:

  • KSHTMLWriter.h
  • KSHTMLWriter.m

For WebKit DOM integration, add:

  • DOM/*

and link to WebKit.framework

Potentially KSHTMLWriter could be built into a framework or static library instead. If you want to do this, feel free to make a fork and add this support; I'll be happy to pull it back into the master.


###KSXMLWriter### KSXMLWriter provides the real meat of the project. Creating elements is very straightforward, and can be thought of as NSXMLParser in reverse. So to write this XML:


you'd do:

[writer startElement:@"foo" attributes:nil];
[writer writeCharacters:@"bar"];
[writer endElement];

Simples! As you can probably see there's easy support for writing element attributes if you need it. Other features:

  • Call -startElement:… multiple times to nest elements inside of each other
  • KSXMLWriter keeps a stack so you can do -endElement and the correct end tag will be written
  • Nested elements are pretty printed with correct newlines and indentation
  • Empty elements are automatically written as <foo />
  • Built-in -writeComment: support

If you need it, there's lower-level API to give precise control over indentation, inline elements, raw text, and element primitives. For more info, read through KSXMLWriter.h.

###KSHTMLWriter### If you specifically need to generate (X)HTML, use KSHTMLWriter. It adds:

  • Many convenience methods for writing common HTML elements and attributes
  • Knowledge of whether an element should be written inline or on its own newline
  • If you enable it, support for HTML 4 and earlier by writing empty elements as <br>

###KSWriter### KSXMLWriter and KSHTMLWriter know how to generate markup, but don't deal with storing that during writing. Instead, we copy a small portion of Java by adopting the concept of a "writer".

You provide the XML writer with a suitable output writer at initialization time. To make life easy for you, NSMutableString is already supported. So to re-use our previous example, you would do:

NSMutableString *xml = [NSMutableString string];
KSXMLWriter *writer = [[KSXMLWriter alloc] initWithOutputWriter:xml];

[writer startElement:@"foo" attributes:nil];
[writer writeCharacters:@"bar"];
[writer endElement];

This will neatly append the markup to the mutable string.

You can easily expand support by adopting KSWriter in your own classes. For example, a class that writes directly to disk, rather than an in-memory buffer. KSXMLWriter itself already adopts the protocol too, so you could chain multiple writers together if it took your fancy. I'm very interested in adding any new writers people come up with to the project.

###KSStringWriter### KSStringWriter is a great example of a simple class that implements KSWriter. It provides an internal buffer for storing the incoming strings. You can then retrieve the currently written text with a call to -string.

This isn't all that different to writing directly to an NSMutableString though, so KSStringWriter has a trick up its sleeve. The most expensive aspect of building up a long string is reallocating the underlying buffer to meet demand. KSStringWriter lets you work around this by recycling the same writer object. After it's done generating the first string, call -removeAllCharacters to reset the written string. It will return to empty, but not free up memory from the old string. The next sequence of writes can be performed quickly into the pre-allocated space, saving time.

If you do need to reclaim the memory, a call to -close will do so.

###XML Entity Escaping### As a bonus, we expose KSStringXMLEntityEscaping.h/m. It exposes what KSXMLWriter is using internally whenever strings need escaping.

This is probably an area of the project that needs cleaning up though: better method naming (ks as a prefix or similar), documentation, and improved efficiency.

###DOM Integration### In DOM/KSHTMLWriter+DOM you'll find code that takes a DOMElement (using WebKit.framework, so no iOS support, sorry!) and breaks it up into a series of commands for KSHTMLWriter. This is a lot like -[DOMElement outerHTML] etc., but more flexible as you can subclass to get hooks into the process if you wish.


iOS support would be nice in the project. There's nothing to stop it that I can see (indeed, it may actually work at the moment for all I know!), but it's not a priority for us right now. If you do want this support, fork, and again I'll be more than happy to pull back into the main project.


Currently Sandvox targets pre-blocks OS releases, but we'd still like to get blocks support in one day. Something like -[KSXMLWriter writeElement:attributes:contents:]. Are you up to the task? Fork it!


It would be nice to apply a similar technique to generating CSS if appropriate. We don't particularly need it at that moment, but there is a placeholder for getting started with in the CSS directory.


The usual BSD license. Use in any way you like; please credit us!

Thanks for reading.