Problem processing XML data with TBXML
I have a .NET web service I have to connect to, and unfortunately, I can't change the web service. I built the web service call with NSURLConnection, and I receive the response fine.
I take the NSData object I'm receiving from the web service call, and when calls the connectionDidFinishLoading method, I'm writing the data to a file. This also works great, no issues.
I take the file path and load it into the TBXML class. When I try to load it via the initWithXMLFile, it never actually ret开发者_C百科urns data from the file. I load the file into an NSData object and use initWithXMLData and things load up fine.
The problem happens when I actually process the file. First, I get the root element, then parse out the extra SOAP headers. When I get into the nested pieces of my data, I set up loops to process them.
TBXMLElement *root = parser.rootXMLElement;
if (root) {
TBXMLElement *soapBody = [TBXMLElement childElementNamed:@"soap:Body" parentElement:root];
TBXMLResponse *serviceResponse = [TBXMLElement childElementNamed:@"GetServiceResponse" parentElement:soapBody];
... more code like this ...
TBXMLElement *mainObject = [TBXML childElementNamed:kMainObject parentElement:parentObject];
while (mainObject != nil) {
TBXMLElement *element1 = [TBXML childElementName:kElement1 parentElement:mainObject];
object.value1 = [TBXML textForElement:element1];
... more nesting and value getting like this ...
mainObject = [TBXML nextSiblingName:kMainObject searchFromElement:mainObject];
}
}
Here's how my data would look:
< ... soap stuff ... >
<mainObject>
<element> ... </element>
<element> ... </element>
<element> ... </element>
<childObjects>
<childObject> ... </childObject>
<childObject> ... </childObject>
<childObject> ... </childObject>
</childObject>
</mainObject>
So, to handle the wrapper ( tag) around the childObject elements, I just pull out the childObjects element, and then set up a loop for everything nested within that element. Like:
// Go into the childObjects wrapper
TBXMLElement *childObjectsWrapper = [TBXML childElementNamed:kChildObjectsWrapper parentElement:parent];
// Get the first childObject element
TBXMLElement *childObject = [TBXML childElementNamed:kChildObject parentElement:parent];
while (childObject != nil) {
... process the nested elements ...
childObject = [TBXML nextSiblingNamed:kChildObject searchFromElement:childObject];
}
1 time out of 10, everything processes just fine. But, 9 times out of 10, it throws an EXC_BAD_ACCESS in the childElementNamed function in the TBXML library. The part of the XML it chokes on is variable. 60% of the time, it's one particular element. 40% of the time it's a random assortment of other elements.
The exception hits at the TBXMLElement *childObject definition, after loading up the wrapper object. I'm sure it's something with the wrapper object, because in the childElementNamed: method, the aParentXMLElement is null. But, the data is there in the XML file as the parser expects it, and it works sometimes. And the data I'm getting back is always the same.
Any help diagnosing this? I'm lost...
Have you considered switching to use some standard SOAP library for Objective-C:
How to access SOAP services from iPhone
Much easier that writing your own SOAP handler from scratch.
The issue turned out to be an XML issue. The data that was being read by the TBXML library had some escaped special characters, in particular &. To fix it, I take the NSData object, convert it to a string, use Google's character escaping class to UNescape the &, and rewrite it to an NSData object. I could just parse the string at that point, but I already had the parser set up for NSData so I've kept it that way for now.
精彩评论