I'm looking for a short example/tutorial on how to read, mod开发者_C百科ify one value and write an xml file using cocoa. Everything that I found is either to simple (just read or write) or to complex (being a full xml editor).
This seems like a pretty standard usage scenario, so I'm hoping that there is something out there...
I was in error, when I claimed that writing such elements couldn't be done. Apple have two XML parsers, one for NSDictionary/NSArray/NSString/NSNumber/etc. objects and one called NSXMLDocument.
I've removed the previous code, which was Mac OS X 10.3 compatible; the code mentioned below will allow you to have xml files containing whatever tags and attributes you like. In my example, the code will create an XML file that looks like the following:
<root><counter>1</counter></root>
Note: You can even remove the 'counter' and rename 'root' to 'counter', if you want to reduce it further.
The new code is compatible with Mac OS X 10.4 and forward; it's tested and works out-of-the-box:
- (void)incrementCounter
{
NSXMLDocument *xmlDoc;
NSError *error;
NSURL *url;
NSXMLElement *root;
id item;
NSData *data;
NSArray *children;
int counter;
NSString *pathname;
pathname = [@"~/myFile" stringByExpandingTildeInPath];
url = [NSURL fileURLWithPath:pathname];
xmlDoc = [[NSXMLDocument alloc] initWithContentsOfURL:url options:NSXMLDocumentTidyXML error:&error];
if(xmlDoc)
{
root = [xmlDoc rootElement];
}
else
{
root = [NSXMLNode elementWithName:@"root"];
xmlDoc = [[NSXMLDocument alloc] initWithRootElement:root];
}
// fetch value:
children = [root nodesForXPath:@"counter" error:&error];
item = [children count] ? [children objectAtIndex:0] : NULL;
// modify value:
counter = item ? [[item stringValue] intValue] : 0;
counter++;
if(NULL == item)
{
item = [NSXMLNode elementWithName:@"counter" stringValue:@"0"];
[root insertChild:item atIndex:0];
}
[item setStringValue:[[NSNumber numberWithInt:counter] stringValue]];
// write:
data = [xmlDoc XMLData];
[data writeToURL:url atomically:YES];
}
Here is my solution to the problem - only the part where I write out the file which was previously read and parsed...
Using the solution of PacMan-- I encountered the problem that the output xml file wasn't formatted nicely (no line breaks at all).
The other point is, I usally prefer using XPath navigating through a XML document.
My code is part of a class, so I have a property for each node (NSString* cfaLayout and NSInteger bitsPerPixel):
-(BOOL) savePropertiesFile{
BOOL isSuccess=FALSE;
NSError* error;
NSXMLElement* currentElement;
NSArray* nodes;
/* parse existing url file before saving it to new url */
if([_documentUrl checkResourceIsReachableAndReturnError:&error]==YES){
self.document=[[NSXMLDocument alloc]
initWithContentsOfURL:_documentUrl
options:0
error:&error];
/* check top node */
nodes=[_document nodesForXPath:@"/ImageFormat-Properties"
error:&error];
if([nodes count]==0){
return FALSE;
}
/* cfa layout */
nodes=[_document nodesForXPath:@"/ImageFormat-Properties/ImageFormatDetails/CFALayout[text()]"
error:&error];
if([nodes count]>0){
currentElement=[nodes objectAtIndex:0];
[currentElement setStringValue:[_cfaLayout lowercaseString]];
}
else{
return FALSE;
}
/* bitsPerPixel */
nodes=[_document nodesForXPath:@"/ImageFormat-Properties/ImageFormatDetails/BitsPerPixel[text()]"
error:&error];
if([nodes count]>0){
currentElement=[nodes objectAtIndex:0];
[currentElement setStringValue:[NSString stringWithFormat: @"%ld", (long)_bitsPerPixel]];
}
else{
return FALSE;
}
}
[_document setDocumentContentKind:NSXMLDocumentXMLKind];
[_document setCharacterEncoding:@"UTF-8"];
[_document validateAndReturnError:&error];
if(error){
return FALSE;
}
[self setDocumentUrl:_documentSaveAsUrl];
NSData* xmlData=[_document XMLDataWithOptions:NSXMLNodePrettyPrint];
isSuccess=[xmlData writeToURL:_documentSaveAsUrl atomically:YES];
return isSuccess;
}
Maybe useful for someone...
If you are not familiar with xpaths, then I suggest you read up on them, xpaths are a way to find nodes in the xml tree.
精彩评论