I've looked all over the web but just can't figure out how to get the text from a node in Objective-C. I'm using TouchXML and I am getting my node list. I want the title text from a node, but instead I get a node object. My code is:
resultNodes = [xmlParser nodesForXPath:#"SearchResults/SearchResult" error:&err];
for (CXMLElement *resultElement in resultNodes) {
NSString *value = [resultElement elementsForName:#"Title"];
}
If I log the value to the console I get:
<CXMLElement 0x3994b10 [0x39732a0] Title <Title HtmlEncoded="true">test question</Title>>
I want the text, i.e test question instead. I am banging my head against a brick wall here.
Since there should atleast one element in "resultElement" for the given value"Title", you can probably access it by adding following line of code:
NSString *value = [[[resultElement elementsForName:#"Title"] objectAtIndex:0] stringValue];
Try:
NSString *value = [[resultElement elementsForName:#"Title"] getStringValue];
Related
I have an NSDictionary that contains an array. What I am trying to do is get the object inside of the first part of my array photoDictionary:
-(NSString*) getImageAtIndex:(NSInteger *)index andObject:(PhotoPXArray *)photoArray {
NSDictionary *photosDictionary = [MTLJSONAdapter JSONDictionaryFromModel:photoArray];
NSArray = [[photosDictionary objectAtIndex:0];
//NSArray *photoCollection = [MTLJSONAdapter JSONArrayFromModels:self.photoPXArray];
return #"ff";
}
This should be really simple but I am banging my head against a wall.
My ultimate goal is to get the 'image_url' as shown in this object model:
Hot Licks answer was PERFECT!!
NSString* url = photosDictionary[#"photos"][0][#"image_url"];
I get an array from a JSON and I parse it into an NSMutableArray (this part is correct and working). I now want to take that array and print the first object to a Label. Here is my code:
NSDictionary *title = [[dictionary objectForKey:#"title"] objectAtIndex:2];
arrayLabel = [title objectForKey:#"label"];
NSLog(#"arrayLabel = %#", arrayLabel); // Returns correct
//Here is where I need help
string = [arrayLabel objectAtIndex:1]; //I do not get the first label (App crashes)
NSLog(#"string = %#", string);
other things that I have already tried are as follows:
string = [NSString stringWithFormat:#"%#", [arrayImage objectAtIndex:1]];
and
string = [[NSString alloc] initWithFormat:#"%#", [arrayImage objectAtIndex:1]];
Any help is greatly appriciated!
EDIT: The app does not return a single value and crashes.
Your code doesn't match the structure of your JSON. In your comment on the deleted answer, you said you got an exception when sending objectAtIndex: to an NSString. In your case, arrayLabel isn't an array when you think it is.
If your JSON has an object, your code needs to treat it as an NSDictionary. Likewise for arrays and NSArray and strings and NSString.
In addition to whatever else was going on, you repeatedly refer to "first" but use the index 1. In most C-based programming languages (and others, as well) the convention is that indexes into arrays are 0-based. So, use index 0 to get the first element.
I am currently using Hpple to parse HTML, like so:
TFHpple *htmlParser = [TFHpple hppleWithHTMLData:[currentString dataUsingEncoding:NSUTF8StringEncoding]];
NSString *paragraphsXpathQuery = #"//p//text()";
NSArray *paragraphNodes = [htmlParser searchWithXPathQuery:paragraphsXpathQuery];
if ([paragraphNodes count] > 0) {
NSMutableArray *tempArray = [NSMutableArray array];
for (TFHppleElement *element in paragraphNodes) {
[tempArray addObject:[element content]];
}
article.paragraphs = tempArray;
}
This way I get an array of paragraphs and I can use NSString *result = [myArray componentsJoinedByString:#"\n\n"]; to compile it into a single body of text with line breakes.
However, if the html contains tags, they are interpreted as individual entities and will get line breaked on their own right, so at the end of the day from a line like this:
<p>I went to the shop to get some milk!</a></p>
<p>It was awesome.</p>
I get this:
I went to the
shop
to get some milk!
It was awesome!
And of course I would like to get this (ignore other tags inside the p tag):
I went to the shop to get some milk!
It was awesome!
Can you help me out?
NSString *HTMLTags = #"<[^>]*>"; //regex to remove any html tag
NSString *htmlString = #"<html>bla bla</html>";
NSString *stringWithoutHTML = [hstmString stringByReplacingOccurrencesOfRegex:myregex withString:#""];
don't forget to include this in your code : #import "RegexKitLite.h" here is the link to download this API : http://regexkit.sourceforge.net/#Downloads
In XPath 1.0 you can do this in two steps:
Select all p elements: //p
On each selected p element (used as the initial context node) evaluate this: string()
Explanation:
By definition, the result of applying the standard XPath function string() to an element is the concatenation (in document order) of all of its text-node descendants.
If I have the following example code:
NSXMLDocument* doc = [[NSXMLDocument alloc] initWithContentsOfURL: [NSURL fileURLWithPath:#"file2.xml"] options:0 error:NULL];
NSXMLElement* root = [doc rootElement];
NSArray* objectElements = [root nodesForXPath:#"//object" error:nil];
NSLog (#"doc - %#", doc);
NSXMLElement *c1 = [objectElements objectAtIndex:0];
NSLog (#"c1 --> %#",[c1 stringValue]);
//creating new element
NSXMLElement *c2 = [NSXMLElement elementWithName:#"value" stringValue:#"object new node"];
[c1 replaceChildAtIndex:0 withNode:c2];
NSLog (#"New doc - %#", doc);
I am trying to get an XML element and change its value to another (c2). The problem is that with the new node replacing, I am getting the element name as well inserted into the XML Document.
So, if I have
<element>old value</element>,
I am now getting:
<element><newElement>new value</newElement></element>
How can I program the code so that
<newElement></newElement>
do not get displayed? Thanks
P.S. Even simpler way of explaining:
Basically, I want to replace an Element with another element. So from
<e1>data1</e1>
I want to have
<e2>data 2</e2>
in its place.
I may be misunderstanding the question but it sounds like you are just trying to make the first element have the second ones attributes? Try something like:
- (void) method {
NSArry* attrs = [c2 attributes];
[c1 setAttributes: attrs];
}
Hope that helps.
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.
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"];
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 (< | >) but I'm guessing that it's not something that simple, considering who you are. :)