Xml parsing in Iphone and adding values to NSMutableArray - iphone

I am new to xml parsing. I have the following xml
<myMainList>
<mySubList>
<edited>true</edited>
<mySharedNumber>W59QYBZKJ4</mySharedNumber>
</mySubList>
<mySubList>
<edited>false</edited>
<mySharedNumber>TOW4KLP9WD</mySharedNumber>
</mySubList>
<mySubList>
<edited>true</edited>
<mySharedNumber>XH8JDIZA64</mySharedNumber>
</mySubList>
<mySubList>
<edited>false</edited>
<mySharedNumber>V2YOHSNODT</mySharedNumber>
</mySubList>
</myMainList>
I have edited my question.
I am not familiar with looping through the whole xml and adding the values into my array. Can someone show me how I can add the 4 sharedNumberList values into my array.
Edit:
GDataXMLElement *node;

NSArray * array = [node nodesForXPath:#"//return/myMainList/mySubList" error:nil];
NSLog(#"count :%d",[array count]);
int sharedContacts = [array count];
NSMutableArray *mySharedListArray = [[NSMutableArray alloc]init];
for(int i = 1; i<= sharedContacts; i++){
NSString *xmlDataFetcher = [NSString stringWithFormat:#"//return/myMainList/mySubList[%d]",i ];
NSString *parsedNumbers = [node nodeStringForXPath:[xmlDataFetcher stringByAppendingString:#"/mySharedNumber"]];
NSString *parsedEdit = [node nodeStringForXPath:[xmlDataFetcher stringByAppendingString:#"/edited"]];
NSLog(#"Parsed Edited %#", [node nodeStringForXPath:[xmlDataFetcher stringByAppendingString:#"/edited"]]);
NSLog(#"Parsed sharedNumber %#", [node nodeStringForXPath:[xmlDataFetcher stringByAppendingString:#"/mySharedNumber"]]);
NSString *arrayEntry = [NSString stringWithFormat:#"%#%#", parsedNumbers, parsedEdit];;
[mySharedListArray addObject:arrayEntry];
}
NSLog(#"Array entry %#", mySharedListArray);
I have added a lot of NSLog in the answer, so that you could log it as you wish

I haven't done this most probably this is returning an array from the xpath query so Try this instead
[mySharedListArray addObjectsFromArray:[node nodesForXPath:#"//return/MyList" error:nil]];

Related

Reading from NSMutableArray throws exception at item 2 even though it exists

I've got a file with a bunch of string in like so:
item1,01-SR,admin,Missing or broken,undefined, 16/04/2013 18:10:10;
item1,03-SR,admin,In Use,undefined, 16/04/2013 18:10:34;
item1,01-SR,admin,In Use,undefined, 16/04/2013 18:10:45;
item1,02-SR,admin,In Use,undefined, 16/04/2013 18:10:49;
item1,05,admin,In Use,undefined, 16/04/2013 18:10:56;
I'm reading the strings in and then splitting them up so I just get one string at a time. Then I want to split up the string I've got again so each CSV is it's own variable. I've tried this like so (numLines is a count of the number of lines in the file):
while (count1 < numLines) {
NSString *message = [[strings objectAtIndex: count1] copy];
NSMutableArray *items = [[fileContents componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#";"]] mutableCopy];
NSString *items1 = [[items objectAtIndex: count1] copy];
NSLog(#"items: %#", items1);
NSMutableArray *inditems = [[items1 componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#","]] mutableCopy];
NSString * item1 = inditems[0];
NSString * bnum1 = inditems[1];
NSString * user1 = inditems[2];
NSString * state1 = inditems[3];
NSString * gender1 = inditems[4];
NSString * tstamp1 = inditems[5];
NSLog(#"item: %#", item1);
NSLog(#"bnum: %#", bnum1);
NSLog(#"user: %#", user1);
NSLog(#"state: %#", state1);
NSLog(#"gender: %#", gender1);
NSLog(#"tstamp: %#", tstamp1);
count1++;
}
Now, this works as far as selecting one line from the file and it puts the first two items into the array and then writes the values of item1 and bnum1 to the log but then it throws an exception for some reason. Now this would usually suggest to me that item 2 doesn't exist in the array so I did a count like so:
NSLog(#"count = %d", [inditems count]);
Which correctly returns 6. I then wanted to check that it could actually read another item from the array so I did:
NSString *tstamp1 = [[inditems lastObject] copy];
Which when logged correctly returns the time stamps like so:
16/04/2013 18:10:10
So I thought "oh at least item 5 works" and tried just getting that item:
while (count1 < numLines) {
NSString *message = [[strings objectAtIndex: count1] copy];
NSMutableArray *items = [[fileContents componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#";"]] mutableCopy];
NSString *items1 = [[items objectAtIndex: count1] copy];
NSLog(#"items: %#", items1);
NSMutableArray *inditems = [[items1 componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#","]] mutableCopy];
NSString * item1 = inditems[0];
NSString * bnum1 = inditems[1];
NSString * tstamp1 = inditems[5];
NSLog(#"item: %#", item1);
NSLog(#"bnum: %#", bnum1);
NSLog(#"tstamp: %#", tstamp1);
count1++;
}
But that also throws an exception! I'm probably doing something stupid here, but I would appreciate any help.
Thanks!
My guess is your NSArray *strings is including empty value which is causing your error. You need to check it first and then do your logic.
//path is your file path
NSString* fileContents = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
NSArray *strings = [fileContents componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
for (int i = 0; i < [strings count]; i++){
if (![[strings objectAtIndex:i] isEqualToString:#""]){
//Here do your code...
}
}

How can I parse this xml using GDataXML parser?

<list>
<OrderData HASH="1408108039"></OrderData>
<OrderData HASH="208524692">
<id>97</id>
<customer>
<CustomerData HASH="2128670187"></CustomerData></customer>
<billingAddress></billingAddress><deliveryAddress></deliveryAddress>
<orderDetail>
<list>
<OrderDetailData HASH="516790072"></OrderDetailData>
<OrderDetailData HASH="11226247"></OrderDetailData>
<OrderDetailData HASH="11226247"></OrderDetailData>
</list>
</orderDetail>
<log/>
</OrderData>
<OrderData HASH="1502226778"></OrderData>
</list>
I cannot find a solution to find the number of OrderDetailData elements? I also read http://iphonebyradix.blogspot.com/2011/03/using-gdata-to-parse-xml-file.html this url.
Thanks in advance.
Edit:
I am explaining my requirement again. In this xml there will be multiple OrderData element. Now I have to count the number of OrderDetailData elemnts from a particular OrderData element. Suppose that, according to my xml, the current parsed xml has one OrderData element, named id and its value is 97. Now, I have to count how many OrderDetailData elements are contained in the OrderData(whichid` is 97).
This is a simple example how to retrieve some data. This example is very simple and not use XPath expression. I suggest you first understand how it works and then use XPath expression. In my opinion it is not useful to use XPath expression if you cannot understand how the parser works.
NSString* path = [[NSBundle mainBundle] pathForResource:#"test2" ofType:#"xml"];
NSData *xmlData = [[NSMutableData alloc] initWithContentsOfFile:path];
NSError *error;
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:xmlData
options:0 error:&error];
//NSLog(#"%#", doc.rootElement); // print the whole xml
NSArray *orderDataArray = [doc.rootElement elementsForName:#"OrderData"];
for (GDataXMLElement *orderDataElement in orderDataArray) {
if([orderDataElement childCount] > 0)
{
NSString *attributeForOrderDataElement = [(GDataXMLElement *) [orderDataElement attributeForName:#"HASH"] stringValue];
NSLog(#"attributeForOrderDataElement has value %#", attributeForOrderDataElement);
GDataXMLElement* idElement = (GDataXMLElement*)[[orderDataElement elementsForName:#"id"] objectAtIndex:0];
NSLog(#"id has value %#", idElement.stringValue);
GDataXMLElement* orderDetailElement = (GDataXMLElement*)[[orderDataElement elementsForName:#"orderDetail"] objectAtIndex:0];
GDataXMLElement* listElement = (GDataXMLElement*)[[orderDetailElement elementsForName:#"list"] objectAtIndex:0];
NSArray* orderDetailDataArray = [listElement elementsForName:#"OrderDetailData"];
int count = 0;
for (GDataXMLElement *orderDetailDataElement in orderDetailDataArray) {
NSString *attributeForOrderDetailDataElement = [(GDataXMLElement *) [orderDetailDataElement attributeForName:#"HASH"] stringValue];
NSLog(#"attributeForOrderDetailDataElement has value %#", attributeForOrderDetailDataElement);
count++;
}
NSLog(#"%d", count);
}
}
[doc release];
[xmlData release];
This is the output console:
attributeForOrderDataElement has value 208524692 <-- HASH value
id has value 97 <-- id value
attributeForOrderDetailDataElement has value 516790072 <-- HASH value
attributeForOrderDetailDataElement has value 11226247
attributeForOrderDetailDataElement has value 11226247
3 <-- the count
Hope it helps.
Edit
test2.xml contains your file but you could pass it as a string. You can also pass as parameters as string like the following:
NSString* xmlString = #"<list>"
"<OrderData HASH=\"1408108039\"></OrderData>"
"<OrderData HASH=\"208524692\">"
"<id>97</id>"
"<customer>"
"<CustomerData HASH=\"2128670187\"></CustomerData>"
"</customer>"
"<billingAddress></billingAddress>"
"<deliveryAddress></deliveryAddress>"
"<orderDetail>"
"<list>"
"<OrderDetailData HASH=\"516790072\"></OrderDetailData>"
"<OrderDetailData HASH=\"11226247\"></OrderDetailData>"
"<OrderDetailData HASH=\"11226247\"></OrderDetailData>"
"</list>"
"</orderDetail>"
"<log/>"
"</OrderData>"
"<OrderData HASH=\"1502226778\"></OrderData>"
"</list>";
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithXMLString:xmlString options:0 error:&error];
I found TouchXML easy in parsing and you can directly access data needed from xml
First of all Download TouchXML and add libxml2.dylib framework to your project.
change buildsetting for "Header Search Path" and add "/usr/include/libxml2"
Import TouchXML.h to your file
//Access document
CXMLDocument *parserDoc = [[CXMLDocument alloc] initWithContentsOfURL:url options:0 error:&err];
//Access root element and access children in heirarchy
CXMLElement *root = [parserDoc rootElement];
NSArray *places = [[[root children] objectAtIndex:0] children];
Else
//Access node by node
NSString *location =[[[[[parserDoc nodesForXPath:#"/xml_api_reply/weather/forecast_information/city" error:nil] objectAtIndex:0] attributeForName:#"data"] stringValue] retain];
If the OrderDetailData is present in 2nd object of array all the time, u can use the below
NSArray* arr = [[XMLelement elementForName:#"list"] elementsForName:#"OrderData"];
NSXMLElement* listElement = [[[arr objectAtIndex:1] elementForName:#"orderDetail"] elementForName:#"list"];
NSArray* orderDetailArray* = [listElement elementsForName:#"OrderDetailData"];
In this u can get the OrderDetailData elements in the array, and u can parse the data in loop. to get HASH value use.
NSString* hash = [[orderDetailArray objectAtIndex:0] stringValueForAttribute:#"HASH"];
This is the below code, i have tried. I got the right output.. check out
NSString* xmlString = #"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<list>"
"<OrderData HASH=\"1408108039\"></OrderData>"
"<OrderData HASH=\"208524692\">"
"<id>97</id>"
"<customer>"
"<CustomerData HASH=\"2128670187\"></CustomerData></customer>"
"<billingAddress></billingAddress><deliveryAddress></deliveryAddress>"
"<orderDetail>"
"<list>"
"<OrderDetailData HASH=\"516790072\"></OrderDetailData>"
"<OrderDetailData HASH=\"11226247\"></OrderDetailData>"
"<OrderDetailData HASH=\"11226247\"></OrderDetailData>"
"</list>"
"</orderDetail>"
"<log/></OrderData>"
"<OrderData HASH=\"1502226778\"></OrderData>"
"</list>";
NSXMLDocument* doc = [[NSXMLDocument alloc] initWithData:[xmlString dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
NSXMLElement* rootElement = [doc rootElement];
NSArray* arr = [rootElement elementsForName:#"OrderData"];
NSXMLElement* orderDataElement;
for (int i = 0; i < [arr count]; i++)
{
int Id = 0;
Id = [[arr objectAtIndex:i] integerValueForNode:#"id"];
if (Id != 0)
{
orderDataElement = [arr objectAtIndex:i];
break;
}
}
NSArray* orderDetailArray = [[[orderDataElement elementForName:#"orderDetail"]
elementForName:#"list"]
elementsForName:#"OrderDetailData"];
for (int j = 0; j < [orderDetailArray count]; j++)
{
NSLog(#"%#", [[orderDetailArray objectAtIndex:j] stringValueForAttribute:#"HASH"]);
}

Overwriting a plist file with content of a NSMutableArray (first item is always NULL in plist)

I am trying to use plist files to save a list of items from a text
file from a web site. When I first create the plist file and add
items to that, there is no problem. But when I try to remove an item
from plist, it is not removing the index, it only overwrites the
content of this index with NULL. And I tried an other way; I tried to
create a new array without the item I want to remove, and overwrite
plist file with the content of this new array. In this way, the item
I wanted to remove is removed, but surprisingly the first item gets
NULL! A more surprising situation is, I also write it to a new plist
file with same technique, and it is perferct! This is a very
primitive code, unfortunately it didn't worked for me. I searched
plenty of tutorials, but I couldn't overcome. How can I write the
content of a string array to a plist file without extra null objects
and without loosing datas?
========================================================================
I composed a sample code below :
- (IBAction)logFromPlist{
NSMutableArray *arr = [[NSMutableArray alloc] initWithContentsOfFile:[NSHomeDirectory() stringByAppendingPathComponent:#"Documents/data2.plist"]];
NSLog(#"LOG:");
NSLog(#"arrplist count : %d", [arr count]);
for(int a=0; a<[arr count]; a++){
NSLog(#"*** %#", [arr objectAtIndex:a]);
}
}
- (IBAction)logFromPlist2{
NSMutableArray *arr = [[NSMutableArray alloc] initWithContentsOfFile:[NSHomeDirectory() stringByAppendingPathComponent:#"Documents/data3.plist"]];
NSLog(#"LOG:");
NSLog(#"arrplist count : %d", [arr count]);
for(int a=0; a<[arr count]; a++){
NSLog(#"*** %#", [arr objectAtIndex:a]);
}
}
- (IBAction)addValue{
NSString *deger = [field5 text]; //New value text field in IB
NSMutableArray *arr = [[NSMutableArray alloc] initWithContentsOfFile:[NSHomeDirectory() stringByAppendingPathComponent:#"Documents/data2.plist"]];
if(arr == NULL){
arr = [[NSMutableArray alloc] init];
}
[arr addObject:deger];
[arr writeToFile:[NSHomeDirectory() stringByAppendingPathComponent:#"Documents/data2.plist"] atomically:NO];
}
- (IBAction)removeFromPlist{
NSMutableArray *arr2 = [[NSMutableArray alloc] initWithContentsOfFile:[NSHomeDirectory() stringByAppendingPathComponent:#"Documents/data2.plist"]];
if(arr2 != NULL){
NSMutableArray *arr = [[NSMutableArray alloc] init];
NSString *key = [field8 text];
for(int i = 0; i < [arr2 count]; i++){
NSString *cntStr = [[NSNumber numberWithInt:i] stringValue];
if(![cntStr isEqualToString:key]){
NSString *tempDeger = [arr2 objectAtIndex:i];
if(tempDeger != NULL){
[arr addObject:tempDeger];
}else{
NSLog(#"it is NULL");
}
}
}
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtPath:[NSHomeDirectory() stringByAppendingPathComponent:#"Documents/data2.plist"] error:nil]; //I tried this line by removing next line
[arr writeToFile:[NSHomeDirectory() stringByAppendingPathComponent:#"Documents/data2.plist"] atomically:NO]; //It is writing the array to plist but first item is always null
[arr writeToFile:[NSHomeDirectory() stringByAppendingPathComponent:#"Documents/data3.plist"] atomically:NO]; //same technique but everything is ok in this plist
[fileManager copyItemAtPath:[NSHomeDirectory() stringByAppendingPathComponent:#"Documents/data3.plist"] toPath:[NSHomeDirectory() stringByAppendingPathComponent:#"Documents/data2.plist"] error:nil]; // trying to copy correct plist file (data3.plist) to original plist file (plist2), but it does not fix the problem.
}
}
Project file : http://www.ozgunbursalioglu.com/files/plistWork.zip
At least your copyItemAtPath: will always fail since it won't overwrite files (data2.plist already exists).
Try to write your file by setting the automatically to YES
[arr writeToFile:PATH atomically:YES];
And also try to check the BOOL value returned to see if your oerration done successfully

Unable to replace NSArray derived from output of "ps aux" UNIX command

Im trying to replace the 7th index of the array "lines2". The NSMUTABLEARRAY "lines2" is derived from the UNIX command "ps aux", and I suspect that this command returns an array of NSCFStrings. Im basically trying to replace "Ss" with "Ss (Running)" for now. The problem is that I get a SIGABRT error every time The program reaches the part where it tries to replace the particular array element. The code for my viewController is below.
NSLog(#"myString is :%#", myString);
int processID = [myString intValue];
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: #"/bin/ps"];
arguments = [NSArray arrayWithObjects: #"aux", [NSString stringWithFormat:#"%i", processID],nil];
[task setArguments: arguments];
NSPipe *pipe;
pipe = [NSPipe pipe];
//[task setStandardOutput: pipe];
[task setStandardOutput:pipe];
NSFileHandle *file;
file = [pipe fileHandleForReading];
[task launch];
NSData *data;
data = [file readDataToEndOfFile];
NSString *string;
string = [[NSString alloc] initWithData: data
encoding: NSUTF8StringEncoding];
// NSLog(#"%#",string);
NSArray *lines= [string componentsSeparatedByString:#"\n"];
NSString *lastline = [lines objectAtIndex:[lines count]-2];
// NSLog(#"%#",lastline);
lines2= [lastline componentsSeparatedByString:#" "];
NSLog(#"%#",lines2);
for (int i=0; i<[lines2 count]; i++) {
if([[lines2 objectAtIndex:i] isEqualToString:#""]){
[lines2 removeObjectAtIndex:i];
}
}
for (int i=0; i<[lines2 count]; i++) {
if([[lines2 objectAtIndex:i] isEqualToString:#""]){
[lines2 removeObjectAtIndex:i];
}
}
for (int i=0; i<[lines2 count]; i++) {
if([[lines2 objectAtIndex:7] isEqualToString:#"Ss"]){
[[lines2 objectAtIndex:0] replaceObjectAtIndex:7 withObject:#"SS (Running)"];
}
}
Any help is very much appreciated!
Please look at the documentation for the method -componentsSeparatedByString:. The signature is:
- (NSArray *)componentsSeparatedByString:(NSString *)separator
Notice the return type is NSArray. This is an immutable object. You must not change it even if inspecting the returned object (say with a debugger or an NSLog) shows it to actually be mutable. You must respect the API contract. (Read the section of the link entitled "receiving mutable objects".)
That said, the immediate cause of your error is this line:
[[lines2 objectAtIndex:0] replaceObjectAtIndex:7 withObject:#"SS (Running)"];
^^^^^^^^^^^^^^^^^^^^^^^^ This is wrong
lines2 is an array of strings. [lines2 objectAtIndex: 0] is a string. Why are you sending -replaceObjectAtIndex:withObject: to it?
You don't say what the error you're seeing is, but you cannot change the values in the NSArray because an NSArray is an immutable container.
Use an NSMutableArray when you want to make modifications. If you have an NSArray already (as in the return value from -componentsSeparatedByString:), you can get a mutable array by doing this:
NSMutableArray * myMutableArray = [NSMutableArray arrayWithArray:lines2];
NSArray is not mutable. First copy it to an NSMutableArray (e.g. using [NSMutableArray arrayWithArray:]) so you can manipulate it.
Didn't you get any warnings during compilation?

Find indices of duplicates in a NSArray

i have an array like
[chapter,indent,left,indent,nonindent,chapter,chapter,indent,indent,left];
i need to find indexes of duplicates and also non duplicate elements .
how to do this...........give some sample code or logic......
thanks in advance
iam using objective c.....
NSArray *myWords = [string componentsSeparatedByString:#"class=\""];
int count_var=[myWords count];
tmp1=#"";
for(int i=1;i<count_var;i++)
{
str=[NSString stringWithFormat:#"\n%#",[myWords objectAtIndex:i]];
class=[str componentsSeparatedByString:#"\""];
NSString *tmp=[NSString stringWithFormat:#"%#",[class objectAtIndex:0]];
tmp1=[[NSString stringWithFormat:#"%#",tmp1] stringByAppendingString:[NSString stringWithFormat:#"%#",tmp]];
}
t1.editable=NO;
t1.text=tmp1;
NSArray *tempo=[[NSArray alloc]init];
tempo=[tmp1 componentsSeparatedByString:#"\n"];
tempCount=[tempo count];
this is my sample code...in this the array tempo contains all objects from that array i want to get index of duplicate stringsā‰„.
You could build a dictionary mapping the objects to index sets. For every index set, a -count of 1 means no duplicates, > 1 means there are duplicates.
NSArray *arr = [NSArray arrayWithObjects:...];
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
for (NSUInteger i=0; i<[arr count]; ++i) {
id obj = [arr objectAtIndex:i];
NSMutableIndexSet *ids = [dict objectForKey:obj];
if (!ids) {
ids = [NSMutableIndexSet indexSet];
[dict setObject:ids forKey:obj];
}
[ids addIndex:i];
}
NSLog(#"%#", dict);