How can i parse nested xml using GDataXML parser? - iphone

How can I get this <firstName> and <lastName>. I have tried a lot but I have messed up.
<list>
<OrderData HASH="1843180441">
<id>26</id><customer>
<CustomerData HASH="882063912">
<id>1</id>
<sex>Male</sex>
<firstName>admin</firstName>
<lastName>admin</lastName>
<companyName>Individual</companyName>
<userName>admin</userName>
<password>21232f297a57a5a743894a0e4a801fc3</password>
<lastLogin>2012-01-26T12:11:38</lastLogin>
<status>A</status>
<created>2011-09-28T07:01:47</created>
<modified>2012-01-26T12:11:38</modified>
<canChangePassword>Y</canChangePassword>
<isDeleted>false</isDeleted>
<abn/>
<abnBranch/>
<storeCredit>50000.0</storeCredit>
<billingAddress>
<list>
<AddressData HASH="768553743">
<id>2</id>
<firstName>admin</firstName>
<lastName>admin</lastName>
<addressLine1>suite: 1307, 9 Yara Street</addressLine1>
<addressLine2>dgdgdf</addressLine2>
<postCode>3000</postCode>
<suburb>dfgdfg</suburb>
<city>sadf</city>
<phone>4456</phone>
<mobile/>
<fax/>
<active>true</active>
<type>C</type>
<email>afzal.bitmascot#gmail.com</email>
<log/>
</AddressData>
</deliveryAddress>
<purchaseDate>2011-10-03T03:23:48</purchaseDate>
</OrderData>
<OrderData HASH="1569451006"></OrderData>
<OrderData HASH="1449383081"></OrderData>
<OrderData HASH="1438157618"></OrderData>
<OrderData HASH="269308788"></OrderData>
</list>
Till now I have done this.
NSLog(#"Enering in the xml file");
NSArray *getNumberOfOrder = [[xmlDocument rootElement] elementsForName:#"OrderData"];
for(GDataXMLElement *e in getNumberOfOrder){
for(int i =0;i<[[e elementsForName:#"customer"]count];i++){
// All orderd customer name
NSString *orderByFirstString = [[[[e elementsForName:#"customer"] objectAtIndex:0] childAtIndex:2] stringValue];
NSString *orderByLastString = [[[[e elementsForName:#"customer"] objectAtIndex:0] childAtIndex:3]stringValue];
orderByString = [NSString stringWithFormat:#"%# %#",orderByFirstString,orderByLastString];
NSLog(#"order By String: %#",orderByString);
}
}
Cordially appreciate for any help or suggestion.

I would try something like this. I would loop through the XML document, and store it in an array.
Notice the NSLog() which will print to the console and will help you see what is going on.
xmlDocument = [[GDataXMLDocument alloc]initWithData:xmlData options:0 error:nil];
NSArray *temp = [xmlDocument.rootElement elementsForName:#"OrderData"];
for(GDataXMLElement *e in temp) {
[outputArray addObject:e];
NSLog(#"%#", e);
}
Then I would loop through the array, and do something like this when I wanted to retrieve a result such as the customer's first name.
for (int i = 0; i < [outputArray count]; i++) {
NSString *firstName = [[[[[[[[outputArray objectAtIndex:i]elementsForName:#"customer"] objectAtIndex:0] elementsForName:#"CustomerData"] objectAtIndex:0] childAtIndex:2]stringValue];
}

Related

unable to parse xml using touchXML, nodesForXPath return nothing

I am trying to parse xml using the touchXML library but not getting the results, the code is as below
NSError *error = nil;
CXMLDocument *xmlParser = [[CXMLDocument alloc] initWithXMLString:dataString options:0 error:&error];
NSArray *resultNodes = NULL;
resultNodes = [xmlParser nodesForXPath:#"//entry" error:&error];
for (CXMLElement *resultElement in resultNodes) {
NSMutableDictionary *blogItem = [[NSMutableDictionary alloc] init];
int counter;
for(counter = 0; counter < [resultElement childCount]; counter++) {
[blogItem setObject:[[resultElement childAtIndex:counter] stringValue] forKey:[[resultElement childAtIndex:counter] name]];
}
}
the method nodesForXPath: doesn't returns anything leaving the resultNodes array with 0 objects. I am getting the proper xml in dataString and the CXMLDocument is also getting prepared properly. I tried debugging it but there is nothing I can see accept the 0 objects in resultNodes, NSError also contains nothing (i.e. no error occurs). the xml file I am trying to parse is as below.
<feed xmlns:s="http://syndication.nhschoices.nhs.uk/services" xmlns="http://www.w3.org/2005/Atom">
<title type="text">...</title>
<id>...</id>
<rights type="text">© Crown Copyright 2009</rights>
<updated>2012-04-27T11:33:02+01:00</updated>
<category term="Search"/>
<logo>...</logo>
<author>...</author>
<s:SearchCoords>174900,517900</s:SearchCoords>
<entry>
<id>
http://v1.syndication.nhschoices.nhs.uk/organisations/gppractices/32248
</id>
<title type="text">Sayer A</title>
<updated>2012-04-27T10:33:02Z</updated>
<link rel="self" title="Sayer A" href="http://v1.syndication.nhschoices.nhs.uk/organisations/gppractices/32248?apikey=YAHUGHET"/>
<link rel="alternate" title="Sayer A" href="http://www.nhs.uk/ServiceDirectories/Pages/GP.aspx?pid=15F37AEF-EC5B-4A90-9E72-269ADEB39629"/>
<content type="application/xml">
<s:organisationSummary>
<s:name>Sayer A</s:name>
<s:address>
<s:addressLine>The Richmond Green Medical Cen</s:addressLine>
<s:addressLine>19 The Green</s:addressLine>
<s:addressLine>Richmond</s:addressLine>
<s:addressLine>Surrey</s:addressLine>
<s:postcode>TW91PX</s:postcode>
</s:address>
<s:contact type="General">
<s:telephone>020 83327515</s:telephone>
</s:contact>
<s:geographicCoordinates>
<s:northing>174900</s:northing>
<s:easting>517800</s:easting>
<s:longitude>-0.305512266736965</s:longitude>
<s:latitude>51.4608026642546</s:latitude>
</s:geographicCoordinates>
<s:Distance>0.1</s:Distance>
</s:organisationSummary>
</content>
</entry>
<entry>
<id>
http://v1.syndication.nhschoices.nhs.uk/organisations/gppractices/33420
</id>
<title type="text">Griffiths W</title>
<updated>2012-04-27T10:33:02Z</updated>
<link rel="self" title="Griffiths W" href="http://v1.syndication.nhschoices.nhs.uk/organisations/gppractices/33420?apikey=YAHUGHET"/>
<link rel="alternate" title="Griffiths W" href="http://www.nhs.uk/ServiceDirectories/Pages/GP.aspx?pid=EEC98A8A-B888-4F44-A0B6-DC6ABCBF19CE"/>
<content type="application/xml">
<s:organisationSummary>
<s:name>Griffiths W</s:name>
<s:address>
<s:addressLine>Paradise Road Surgery</s:addressLine>
<s:addressLine>37 Paradise Road</s:addressLine>
<s:addressLine>Richmond</s:addressLine>
<s:addressLine>Surrey</s:addressLine>
<s:postcode>TW91SA</s:postcode>
</s:address>
<s:contact type="General">
<s:telephone>020 89402423</s:telephone>
</s:contact>
<s:geographicCoordinates>
<s:northing>174800</s:northing>
<s:easting>518100</s:easting>
<s:longitude>-0.301388352909701</s:longitude>
<s:latitude>51.4601120315006</s:latitude>
</s:geographicCoordinates>
<s:Distance>0.223606797749979</s:Distance>
</s:organisationSummary>
</content>
</entry>
<entry>
<id>
http://v1.syndication.nhschoices.nhs.uk/organisations/gppractices/33035
</id>
<title type="text">Dr Da Costa</title>
<updated>2012-04-27T10:33:02Z</updated>
<link rel="self" title="Dr Da Costa" href="http://v1.syndication.nhschoices.nhs.uk/organisations/gppractices/33035?apikey=YAHUGHET"/>
<link rel="alternate" title="Dr Da Costa" href="http://www.nhs.uk/ServiceDirectories/Pages/GP.aspx?pid=EDCE215D-6412-4AAB-AFC4-9F37888D413C"/>
<content type="application/xml">
<s:organisationSummary>
<s:name>Dr Da Costa</s:name>
<s:address>
<s:addressLine>The Vineyard Surgery</s:addressLine>
<s:addressLine>35 The Vineyard</s:addressLine>
<s:addressLine>Richmond</s:addressLine>
<s:addressLine>Surrey</s:addressLine>
<s:postcode>TW106PP</s:postcode>
</s:address>
<s:contact type="General">
<s:telephone>020 89480404</s:telephone>
</s:contact>
<s:geographicCoordinates>
<s:northing>174600</s:northing>
<s:easting>518100</s:easting>
<s:longitude>-0.301044685875553</s:longitude>
<s:latitude>51.4581333717098</s:latitude>
</s:geographicCoordinates>
<s:Distance>0.360555127546399</s:Distance>
</s:organisationSummary>
</content>
</entry>
I've never worked with touchXML, but it may be that you need to set your namespace, like here: Getting the value of an Element in Cocoa using TouchXML
Just check out this , I was able to parse the similar kind of response :
- (void)viewDidLoad
{
[super viewDidLoad];
self.rqst=[[WebRqst alloc] init];
[self.rqst startLoading:[NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"PASS UR URL"]]
vCtr:self];
}
**// a method to grab the attributes.**
- (void)parseAttributesForElement:(CXMLElement*)element andDictionary:(NSMutableDictionary*)dictionary {
NSString *strName,*strValue;
NSArray *arAttributes = [(CXMLElement*)element attributes];
for (int i=0; i<arAttributes.count; i++) {
strName = [[arAttributes objectAtIndex:i] name];
strValue = [[arAttributes objectAtIndex:i] stringValue];
if(strName && strValue && [strName length]>0 && [strValue length]>0) {
[dictionary setValue:strValue forKey:strName];
}
}
}
**// a method to parse the node & store in dictionary**
- (void)parseThisNode:(CXMLNode*)node storeInDictionary:(NSMutableDictionary*)dOfNode {
NSString *strName = [node name];
NSString *strValue = [node stringValue];
if(strName && [strName length]>0 && ![strName isEqualToString:#"text"]) {
NSMutableDictionary *dOfAttributes = [NSMutableDictionary dictionary];
// if node has value
if(strValue && [strValue length]>0) {
[dOfAttributes setValue:strValue forKey:#"value"];
}
// if node has attributes
if([node isKindOfClass:[CXMLElement class]] && [(CXMLElement*)node attributes].count>0) {
[self parseAttributesForElement:(CXMLElement*)node andDictionary:dOfAttributes];
}
// if node has childs
NSArray *arChildern = [node children];
if(arChildern.count>0) {
NSMutableDictionary *dOfTAG=[NSMutableDictionary dictionary];
for (CXMLNode *nodeChildChild in arChildern) {
// recursive call of a function
[self parseThisNode:nodeChildChild storeInDictionary:dOfTAG];
}
if([[dOfTAG allKeys] count]>0) [dOfAttributes setValue:dOfTAG forKey:#"child"];
}
id valueFK = [dOfNode valueForKey:strName];
// verify if same node is repeated, add it to array (e.g. link tag is repeated )
if([valueFK isKindOfClass:[NSMutableArray class]]) {
NSMutableArray *ar=(NSMutableArray*)valueFK;
[ar addObject:dOfAttributes];
[dOfNode setValue:ar forKey:strName];
} else if([valueFK isKindOfClass:[NSMutableDictionary class]]) {
NSMutableArray *ar=[NSMutableArray arrayWithObjects:valueFK,dOfAttributes, nil];
[dOfNode setValue:ar forKey:strName];
} else {
[dOfNode setValue:dOfAttributes forKey:strName];
}
}
}
**// pass the data to this method & it will return a dictionary**
- (NSDictionary *)startParsingUsingData:(NSData *) data {
// create a mutable-empty dictionary wich will hold the data
NSMutableDictionary *dictionaryParsed = [NSMutableDictionary dictionary];
// verify - do we have proper data for parsing or not
if(data && [data length]>0) {
// load a data into XML Document
CXMLDocument *doc = [[CXMLDocument alloc] initWithData:data options:0 error:nil];
// grab all the tags of XML
NSArray *nodes = [doc nodesForXPath:#"*" error:nil];
// start a loop to goThrough each tag of xml
for (CXMLNode *nodeFeed in nodes) {
// verify that you reached to desired tag or not
if([[nodeFeed name] isEqualToString:#"feed"]) {
// just write this code to get data parsed & stored in our dictionary
[self parseThisNode:nodeFeed storeInDictionary:dictionaryParsed];
// grab the childrens of tag ( as per requirement )
dictionaryParsed=[[dictionaryParsed valueForKey:#"feed"] valueForKey:#"child"];
}
}
}
// return the dictionary.
if([[dictionaryParsed allKeys]count]>0) {
return [NSDictionary dictionaryWithDictionary:dictionaryParsed];
} else {
return nil;
}
}
// It's my delegate method where I am getting my NSData
- (void)webRequestReceivedData:(NSData *)data {
if(data && [data length]>0) {
NSLog(#"Details are as follows\n%#",
[self startParsingUsingData:data]); //This is the method required which will parse the data
}
}
Hope, now you will be able to parse the data.

Xml parsing in Iphone and adding values to NSMutableArray

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]];

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"]);
}

kissXML returning no values for xpath query

Im trying to parse the following XML file(generated on iphone with KISSxml) with KissXML :
<?xml version="1.0" encoding="UTF-8"?>
<SnowProfile xmlns="http://caaml.org/Schemas/V5.0/Profiles/SnowProfileIACS" xmlns:gml="http://www.opengis.net/gml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://caaml.org/Schemas/V5.0/Profiles/SnowProfileIACS http://caaml.org/Schemas/V5.0/Profiles/SnowprofileIACS/CAAMLv5_SnowProfileIACS.xsd" gml:id="2011-09-04-Home">
<metaDataProperty>
<MetaData>
<dateTimeReport>2011-09-04T18:45:10-0700</dateTimeReport>
<srcRef>
<Operation>
<name>My op</name>
<contactPerson>
<Person>
<name>Jesse</name>
</Person>
</contactPerson>
</Operation>
</srcRef>
</MetaData>
</metaDataProperty>
<validTime>
<TimeInstant>
<timePosition>2011-09-04T18:45:10-0700</timePosition>
</TimeInstant>
</validTime>
<snowProfileResultsOf>
<SnowProfileMeasurements dir="top down">
<comment>Testing</comment>
<profileDepth uom="cm">58</profileDepth>
<skyCond>BKN</skyCond>
<precipTI>None</precipTI>
<airTempPres uom="degC">2</airTempPres>
<windSpd uom="ms-1">5</windSpd>
<windDir>
<AspectPosition>
<position>E</position>
</AspectPosition>
</windDir>
<hS>
<Components>
<snowHeight uom="cm">3</snowHeight>
</Components>
</hS>
<penetrationSki uom="cm">14</penetrationSki>
<penetrationFoot uom="cm">8</penetrationFoot>
<penetrationRam uom="cm">22</penetrationRam>
<stratProfile>
<Layer>
<depthTop uom="cm">0</depthTop>
<thickness uom="cm">27</thickness>
<grainFormPrimary>PPsd</grainFormPrimary>
<grainSize uom="mm">14</grainSize>
<hardness uom="">4F</hardness>
<lwc uom="">W</lwc>
<density uom="kg/m3">310</density>
<validFormationTime>
<timeInstant>
<timePosition>2011-09-05</timePosition>
</timeInstant>
</validFormationTime>
</Layer>
<Layer>
<depthTop uom="cm">27</depthTop>
<thickness uom="cm">31</thickness>
<grainFormPrimary>PPnd</grainFormPrimary>
<grainFormSecondary>PPpl</grainFormSecondary>
<grainSize uom="mm">11</grainSize>
<hardness uom="">1F</hardness>
<lwc uom="">S</lwc>
<density uom="kg/m3">263</density>
<validFormationTime>
<timeInstant>
<timePosition>2011-07-05</timePosition>
</timeInstant>
</validFormationTime>
</Layer>
</stratProfile>
<tempProfile uomDepth="cm" uomTemp="C">
<Obs>
<depth>2</depth>
<snowTemp>0</snowTemp>
</Obs>
<Obs>
<depth>18</depth>
<snowTemp>-4</snowTemp>
</Obs>
<Obs>
<depth>52</depth>
<snowTemp>-1</snowTemp>
</Obs>
</tempProfile>
<stbTests>
<RBlockTest>
<comment>Test</comment>
<failedOn>
<Layer uom="cm">
<depthTop>25</depthTop>
</Layer>
<Results>
<testScore>3</testScore>
<fractureCharacter>Q3</fractureCharacter>
</Results>
</failedOn>
</RBlockTest>
</stbTests>
</SnowProfileMeasurements>
</snowProfileResultsOf>
<locRef>
<ObsPoint>
<name>Home</name>
<validElevation>
<ElevationPosition uom="m">
<position>110</position>
</ElevationPosition>
</validElevation>
<validAspect>
<AspectPosition>
<position>SW</position>
</AspectPosition>
</validAspect>
<validSlopeAngle>
<SlopeAnglePosition uom="deg">
<position>2</position>
</SlopeAnglePosition>
</validSlopeAngle>
<pointLocation>
<gml:Point srsDimension="2">
<gml:pos></gml:pos>
</gml:Point>
</pointLocation>
</ObsPoint>
</locRef>
</SnowProfile>
Using the following code to create a core data object from it:
-(BOOL)importFile:(NSString *)fileName error:(NSError **)error{
NSData *data = [[NSData alloc] initWithContentsOfFile:fileName];
if(data == nil)
return NO;
DDXMLDocument *doc = [[DDXMLDocument alloc] initWithData:data options:0 error:error];
//if(error != nil)
if(doc == nil)
return NO;
snowPit *pit = [snowPit pitForCAAMLProfile:doc];
if(pit != nil)
return YES;
else
return NO;
}
+(snowPit *)pitForCAAMLProfile:(DDXMLDocument *)xmlDoc{
NSLog(#"%#", [xmlDoc XMLStringWithOptions:DDXMLNodePrettyPrint] );
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ssZ"];
NSError *err;
snowPit *newPit = [[pitManager sharedManager] newPitWithoutDefaults];
NSArray *fields = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"CAAMLImportFields" ofType:#"plist"]];
for(NSDictionary *importField in fields){
NSString *field = [importField valueForKey:#"field"];
NSString *xpath = [importField valueForKey:#"xpath"];
NSString *attribute = [importField valueForKey:#"attribute"];
NSArray *nodes;
if(xpath != nil && [xpath length] > 0){
nodes = [xmlDoc nodesForXPath:xpath error:nil];
NSLog(#"Field:%#, xpath:%#, attribute:%# nodes:%i", field, xpath, attribute, [nodes count]);
if(nodes != nil && [nodes count] > 0){
NSString *value;
if(attribute != nil && [attribute length] > 0){
DDXMLNode *attNode = [[nodes objectAtIndex:0] attributeForName:attribute];
if(attNode != nil)
value = [attNode stringValue];
}else
value = [[nodes objectAtIndex:0] stringValue];
if(value != nil && [value length] > 0)
[newPit setValue:value forKey:field];
}
}
}
[dateFormatter release];
return newPit;
}
But so far every XPath query I try returns an array of 0 length.
To get the value for name i have tried //Person/name Person/name //name name And they all return a 0 length array. Even a query for /SnowProfile returns a 0 length array which leads me to think that something is going wrong with the xml parsing. I have validated the XML file and it is fine, and from the NSlog output I can tell that the file is being loaded.
There is a namespace defined xmlns:gml="http://www.opengis.net/gml"
From my recollection of xpath, you need to specify that when you do an xpath query. Try /gml:SnowProfile to see if that returns something other than a 0 length array. You will then know if this will solve your problem.
You have to replace the "xmlns" attribute of the html tag by "noNSxml" to have a correct parsing. If you want to reuse it, it suggest you then ti put buck xmlns.
Rather than processing the file as text and modifying it, the default namespace can be renamed and thus queried. Details are in this answer, with code.

Parsing multiple and multi-level nested elements with TouchXML

I have an XML with the following structure and I am trying to create my model object from this. Can someone please help me find a way to get these objects from the XML using TouchXML, NSMutableArray and NSMutableDictionay.
<?xml version="1.0" encoding="utf-8"?>
<response>
<level1_items>
<level1_item>
<item_1>text</item_1>
<item_2>text</item_2>
</level1_item>
<level1_item>
<item_1>some text</item_1>
<item_2>some more text</item_2>
</level1_items>
<items>
<item>
<child_items>
<child_item>
<leaf1>node text</leaf1>
<leaf2>leaf text</leaf2>
<leaf3>some text</leaf3>
</child_item>
<child_item>
<leaf1>text</leaf1>
<leaf2>leaf text</leaf2>
<leaf3>more text</leaf3>
</child_item>
</child_items>
</item>
<item>
<child_items>
<child_item>
<leaf1>node text</leaf1>
<leaf2>leaf text</leaf2>
<leaf3>some text</leaf3>
</child_item>
<child_item>
<leaf1>text</leaf1>
<leaf2>leaf text</leaf2>
<leaf3>more text</leaf3>
</child_item>
</child_items>
</item>
</items>
</response>
I need to parse the <response> and its children.
First off, I have to say that your XML will be difficult to work with because you are trying to use a specific tag for each item in a list. For example:
<level1_items>
<level1_item>
<item_1>text</item_1>
<item_2>text</item_2>
</level1_item>
<level1_item>
<item_1>some text</item_1>
<item_2>some more text</item_2>
</level1_items>
the tags named <item_ 1>, <item_ 2> don't make sense as XML is intended to describe your data, not define it. If you have an entity called an item, you should probably just call it item and make the XML look like this:
<level1_items>
<level1_item>
<item index="1">text</item>
<item index="2">text</item>
</level1_item>
<level1_item>
<item index="1">some text</item>
<item index="2">some more text</item>
</level1_items>
Where each item has an index. For that matter, you could just load the document in your TouchXML CXMLDocument and grab the nodes you need with XPath and assume they're in the correct order ignoring the index= parameter I specified.
The next issue is that converting XML to an NSDictioanry or NSArray of dictionaries is a pretty involved task and what you gain isn't worth the effort. Just load your XML into a CXMLDocument and then start obtaining nodes using XPath. Something like this:
CXMLDocument *doc = [[CXMLDocument alloc] initWithXMLString:xmlString options:0 error:nil];
// Returns all 'level1_item' nodes in an array
NSArray *nodes = [[doc rootElement] nodesForXPath:#"//response/level1_items/level1_item" error:nil];
for (CXMLNode *itemNode in nodes)
{
for (CXMLNode *childNode in [itemNode children])
{
NSString *nodeName = [childNode name]; // should contain item_1 in first iteration
NSString *nodeValue = [childNode stringValue]; // should contain 'text' in first iteration
// Do something with the node data.
}
}
I suggest trying to use the XML this way and then come back here and ask specific questions if you have problems.
-(NSMutableArray *)parseNodeFromXML:(NSString *)strXML readForNode:(NSString *)strReadValue
{
NSError *theError = NULL;
CXMLDocument *theXMLDocument = [[CXMLDocument alloc] initWithXMLString:strXML options:0 error:&theError] ;
NSMutableArray *arrReturn = [[NSMutableArray alloc] init];
NSArray *nodes = [[theXMLDocument rootElement] nodesForXPath:strReadValue error:nil];
for (CXMLNode *itemNode in nodes)
{
NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
// PROCESS FOR READ ELEMENT ATTRIBUTES IN CURRENT NODE -------------------------
if([itemNode isMemberOfClass:[CXMLElement class]]){
CXMLElement *elements=(CXMLElement*)itemNode;
NSArray *arAttr=[elements attributes];
for (int i=0; i<[arAttr count]; i++) {
if([[arAttr objectAtIndex:i] name] && [[arAttr objectAtIndex:i] stringValue]){
[dic setValue:[[arAttr objectAtIndex:i] stringValue] forKey:[[arAttr objectAtIndex:i] name]];
}
}
}
// PROCESS FOR READ CHILD NODE IN CURRENT NODE -------------------------
for (CXMLNode *childNode in [itemNode children])
{
// NSLog(#"count -- %d --- %#",[childNode childCount],[childNode children]);
// IF ANY CHILD NODE HAVE MULTIPLE CHILDRENS THEN DO THIS....-
if ([childNode childCount] > 1)
{
NSMutableDictionary *dicChild = [[NSMutableDictionary alloc] init];
for (CXMLNode *ChildItemNode in [childNode children])
{
[dicChild setValue:[ChildItemNode stringValue] forKey:[ChildItemNode name]];
}
[dic setValue:dicChild forKey:[childNode name]];
}else
{
[dic setValue:[childNode stringValue] forKey:[childNode name]];
}
}
[arrReturn addObject:dic];
}
// NSLog(#"%#",arrReturn);
return arrReturn;
}
may this help for multiple get child