views:

166

answers:

4

I need to create an XML document with the following type of format.

<Para>

This is some text about <someMethod> that you need to know about.

</Para>

I'm having no issues with general XML generation, but this one aspect is giving me some issues.

Thanks folks

Scott

A: 

Not sure why my correction didn't get posted...

This is some text about the <codeVoice>someMethod</codeVoice> that you need to know about.

That's what I need to replicate.

Scott Anguish
A: 

If <someMethod> is actually an element, then you need to create a NSXMLNode of kind NSXMLTextKind (via initWithKind:), create your <someMethod> node, and create another text node, then add all three in order as children to your <Para> node. The key is creating the two text parts as separate nodes.

After rereading the question, I'm thinking maybe <someMethod> wasn't intended to be a node, but should have been text? If so, it's just an escaping problem (&lt; | &gt;) but I'm guessing that it's not something that simple, considering who you are. :)

pixel
+2  A: 

One approach is to make a mutable copy of the stringValue of the para node and then insert your tags around the "someMethod" text. Create a new NSXMLNode from that using -[NSXMLNode initWithXMLString:error:] and replace the old NSXMLNode with the new NSXMLNode. That's probably shorter, but it requires some string manipulation.

If you know the para node is a single run of text, then you can use this category on NSXMLNode I just wrote which seems a bit more verbose to me than what I described. Depends on what your needs are and how much you like messing around with NSMutableStrings. :)

@implementation NSXMLElement (ElementSplitting)

- (void)splitTextAtRangeInStringValue:(NSRange)newNodeRange withElement:(NSString *)element {
/*  This is pretty simplistic; it assumes that you're attempting to split an element node (the receiver) with a single stringValue. If you need to do anything more complicated, you'll have to do some more work. For this limited example, we need three new nodes(!):
        1. One new text node for the first part of the original string
        2. One new element node with a stringValue of the annotated part of the string
        3. One new text node for the tail part of the original string
    An alternate approach is to use -[NSXMLNode initWithXMLString:error:] after making a mutable copy of the string and modifying that string with the new markup you want.
 */
    NSXMLNode *prefaceTextNode = [[NSXMLNode alloc] initWithKind:NSXMLTextKind];
    NSXMLElement *elementNode = [[NSXMLNode alloc] initWithKind:NSXMLElementKind];
    NSXMLNode *suffixTextNode = [[NSXMLNode alloc] initWithKind:NSXMLTextKind];

    NSString *fullStringValue = [self stringValue];
    NSString *prefaceString = [fullStringValue substringToIndex:newNodeRange.location];
    NSString *newElementString = [fullStringValue substringWithRange:newNodeRange];
    NSString *suffixString = [fullStringValue substringFromIndex:newNodeRange.location + newNodeRange.length];

    [prefaceTextNode setStringValue:prefaceString];
    [elementNode setName:element];
    [elementNode setStringValue:newElementString];
    [suffixTextNode setStringValue:suffixString];

    NSArray *newChildren = [[NSArray alloc] initWithObjects:prefaceTextNode, elementNode, suffixTextNode, nil];
    for (id item in newChildren) { [item release]; }    // The array owns these now.
    [self setChildren:newChildren];
    [newChildren release];
}

@end

...and here's a small example:

NSString *xml_string = @"<para>This is some text about something.</para>";
NSError *xml_error = nil;
NSXMLDocument *doc = [[NSXMLDocument alloc] initWithXMLString:xml_string options:NSXMLNodeOptionsNone error:&xml_error];

NSXMLElement *node = [[doc children] objectAtIndex:0];
NSString *childString = [node stringValue];    
NSRange splitRange = [childString rangeOfString:@"text about"];

[node splitTextAtRangeInStringValue:splitRange withElement:@"codeVoice"];
Chris Parker
I am not worthy. :)
pixel
+1  A: 

Wow, thanks Chris and Pixel.

Yeah, it was a mistake initially that I just used the brackets around the name rather than the codeVoice tag around someMethod.

But all is well now. I'm generating what I need to thanks to you guys.

Scott Anguish