I am creating an NSXMLDocument, from which I get a file defined in a constant USER_PRINTXML_URL, as follows:
NSXMLDocument *ads_user_printxml = [[NSXMLDocument alloc] initWithContentsOfURL: [NSURL URLWithString:USER_PRINTXML_URL] options:(NSXMLNodePreserveWhitespace|NSXMLNodePreserveCDATA) error:&ads_err];
Then I use XPath to get to the desired location in the XML file, as follows:
NSArray* ipp_folder = [[ads_user_printxml nodesForXPath:#".//root/printing/IPP"error:&ads_err] objectAtIndex:0];
Now, if I want to add NSXMLElements after the element in the XML file, how do I do it?
I have tried to do the following:
NSXMLElement *s= [ipp_folder objectAtIndex:0];
But this is generating a run time error. I also tried using an NSXMLNode instead of putting the data in an NSArray but again to no avail. I believe the solution is quite simple, but I can't for the life of me find an answer in the docs.
Thanks for any help.
-nodesForXPath:error: returns an NSArray*, but your second code snippet has already applied -objectAtIndex: to that. So, ipp_folder doesn't hold an array, it holds a pointer to an NSXMLNode. Fix its declared type.
Then, you can identify its parent using the -parent method and its index within the parent's children using the -index method. Then, assuming the parent is an NSXMLElement, you can do:
[[ipp_folder parent] insertChild:someNewNode atIndex:[ipp_folder index] + 1];
Related
I have a very simple HTTP query that runs and grabs some JSON object in another class. I have an NSDictionary object called finalDataArray being defined. I am basically trying to loop through and append names to a table, the number of rows are being calculated correctly. finalDataArray.count
But when I try to do this, I get an error on the first line below.
NSArray *contactArray = [finalDataArray allKeys];
NSLog(#"%#", contactArray);
Because I am such a newb, I didn't realize that if you had a "Miltidimensional" JSON object... it should be NSDictionary, but if you have a single dimenstional object... it should be NSArray which fixes my issue...
Thanks for all the help.
I have an NSXMLElement that is a copy from somewhere else in my code. After it's been used, it no longer is connected to an NSXMLDocument. It's (what I believe to be) not linked to anything.
If I NSLog the NSXMLElement, I am given the contents. I can see it.
But, if I try to use nodesForXPath, it returns nothing. It's blank. It cannot find anything (unless I just search for *, in which case it returns everything with /t/t/n/t/t).
Now, if I make that NSXMLElement the root of a NEW NSXMLDocument, and then search the new document, I can search the XPath perfectly!
I am trying to understand the logic there. I have been reading the documentation, but I haven't found anything that explains what is happening here (or at least, I have no understood it if I did find it in the documentation).
I would really appreciate someone helping me understand exactly why this is happening, and whether or not I need to use this NSXMLDocument.
Here is my code:
(element is an NSXMLElement coming from an NSArray of stored NSXMLElements. They are copies from a document used in another method)
NSArray* scene = [element nodesForXPath:#"scene[1]" error:nil];
NSLog(#"scene: %#", [[scene objectAtIndex:0] stringValue]);
But if I do this, I get a result:
NSXMLDocument* docElement = [[NSXMLDocument alloc] initWithRootElement:element];
NSArray* scene = [docElement nodesForXPath:#"scene[1]" error:nil];
NSLog(#"scene: %#", [[scene objectAtIndex:0] stringValue]);
It's probably because the xpath context used by libxml2 holds a reference to the document. If there is no document, it probably doesn't know how to operate. The behavior if you search for * may just be a special-case because it knows it has to return everything so it doesn't even try to search.
New to Objective-C here...
I have a unique string code as the key that I'd like to use to look up associated values.
It seems an NSDictionary is what I'm looking for but I believe this is only used to lookup one value for a given key.
Can anyone provide the code on how to declare/fill a multidimensional immutable NSDictionary? Also the code to retrieve the values?
Also, please let me know I'm going about this the wrong way
Thanks
EDIT: example of array within a dictionary .... using example data from your comment.
NSMutableDictionary *myDictionary = [[NSMutableDictionary alloc] init];
NSArray *firstSet = [[NSArray alloc] initWithObjects:43, 22];
NSArray *secondSet = [[NSArray alloc] initWithObjects:32, 50];
[myDictionary setValue:firstSet forKey:#"010"];
[myDictionary setValue:secondSet forKey:#"011"];
// Get a value out - should be the 50 that you want
NSInteger *myValue = [[myDictionary objectForKey:#"011"] objectAtIndex:1];
Not tested - but should be 95% right. Does this make sense?
You can make any object you want be the value for a given key in an NSDictionary. This includes NSArray or even another NSDictionary. Using either of these would allow you to associate multiple values with one key.
For nested NSDictionaries or custom KVC-complient classes you can use keyPaths, and for nested NSArrays indexPaths.
Also stackoverflow will give you many examples.
I would like to use entity objects but not store them... I read that I could create them like this:
myElement = (Element *)[NSEntityDescription insertNewObjectForEntityForName:#"Element" inManagedObjectContext:managedObjectContext];
And right after that remove them:
[managedObjectContext deleteObject:myElement];
then I can use my elements:
myElement.property1 = #"Hello";
This works pretty well even though I think this is probably not the most optimal way to do it...
Then I try to use it in my UITableView... the problem is that the object get released after the initialization. My table becomes empty when I move it!
Thanks
edit: I've also tried to copy the element ([myElement copy]) but I get an error...
Maybe you can try to have two store coordinators in your project. One which have persistence, and the other with no persistence.
couldn't you just do
Element *myElement = [[Element alloc] init];
Then do with it whatever you want, presumably you will add it to an array so it says around for your UITableView.
Consider using transient objects --- that are handled by the managed object context like any other object, but not written to disk on a save operation. They are typically employed to model runtime-only objects, as I suspect you are trying to do.
Here is some info on them:
http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CoreData/Articles/cdNSAttributes.html
http://2pi.dk/tech/cocoa/transient_properties.html
One option drawn from an answer to a similar question is initializing the NSManagedObject with a nil context:
Element *myElement = [[Element alloc] initWithEntity:entity
insertIntoManagedObjectContext:nil];
or
Element *myElement = [NSEntityDescription insertNewObjectForEntityForName:#"Element"
inManagedObjectContext:nil];
What I did was using an in-memory store. You can do it as described here: http://commandshift.co.uk/blog/2013/06/06/multiple-persistent-stores-in-core-data/
I am using TouchXml because of the given limitations of NSXML on the actual iPhone. Anyway, I'm just starting out with Objective-C, I come from a C# background, and felt like learning something new..anyhow.. here is my xml file...
<?xml version="1.0" encoding="utf-8"?>
<FundInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://tempuri.org/webservices">
<FundsReleaseDate>2009-02-11T00:00:00</FundsReleaseDate>
<FundValue>7800</FundValue>
<FundShares>1000</FundShares>
</FundInfo>
I'm trying to get 7800, i.e FundValue. Can someone point me in the correct direction, I am using the TouchXml CXMLDocument and myParser is of type CXMLDocument, I have tried
NSArray *nodes = [myParser nodesForXPath:#"//FundInfo" error:&err];
Basically nodes evaluates to nil
if ([nodes count] > 0 ) {
amount = [nodes objectAtIndex:1];
}
UPDATE 1: I have abandoned parsing using XPath, and have replaced it with NSURLRequest, so now I have the entire XML in a string, but my rude introduction to objective-C continues...I just realized how spoiled I have become to the .NET BCL where things like Regex are so easily available.
UPDATE2: I've figured out how to use RegexKitLite for regex.
So the question now is, how do I get the "7800" from inside FundValue which is now one big string. I have confirmed I have it in my NSString by writing it using NSLog.
The problem is that your XML has a namespace, which means your XPath does not actually match. Unfortunately there is no default mapping, and XPath does not actually define a good way to handle this internally, so you can't fix it simply by changing the XPath. Instead you need to inform the interpreter how you want to map it in your XPath.
It looks like TouchXML implements support for this via:
- (NSArray *)nodesForXPath:(NSString *)xpath namespaceMappings:(NSDictionary *)inNamespaceMappings error:(NSError **)error;
So you can try something like:
NSDictionary *mappings = [NSDictionary dictionaryWithObject:#"http://tempuri.org/webservices" forKey:#"tempuri"];
[myParser nodesForXPath:#"//tempuri:FundInfo" namespaceMappings:mappings error:&err];
I had a similar problem. ANY selection on an XML that has a namespace specified (xmlns="http://somenamespace") will result in no nodes found. Very strange considering it does support the additional namespace formats such as xmlns:somenamespace="http://somenamespace".
In any case, by far the easiest thing to do is do a string replace and replace xmlns="http://tempuri.org/webservices with an empty string.
Overall I like touchxml, but I can't believe this bug still exists.
Try
NSArray *nodes = [myParser nodesForXPath:#"/FundInfo/*" error:&err];