NSXMLElement walk through - nsxmlparser

I have an element of a NSXMLDocument (a FCPX exported .fcpxml) which I'd like to walk-through, as opposed to getting the children and then the nested children, etc:
 
    <spine>  
     <clip name="Referee" offset="0s" duration="5s" format="r2" tcFormat="NDF">  
      <video offset="0s" ref="r3" duration="418132800/90000s">  
       <audio lane="-2" offset="0s" ref="r3" srcID="2" duration="3345062400/720000s" role="dialogue" srcCh="1, 2"/>  
       <audio lane="-1" offset="0s" ref="r3" duration="3345062400/720000s" role="dialogue" srcCh="1, 2"/>  
      </video>  
      <spine lane="1" offset="119/25s" format="r1">  
       <clip name="Referee" offset="0s" duration="403200/90000s" start="1300/2500s" format="r2" tcFormat="NDF">  
        <adjust-volume amount="-96dB"/>  
        <video offset="0s" ref="r3" duration="418132800/90000s">  
         <audio lane="-2" offset="0s" ref="r3" srcID="2" duration="3345062400/720000s" role="dialogue" srcCh="1, 2"/>  
         <audio lane="-1" offset="0s" ref="r3" duration="3345062400/720000s" role="dialogue" srcCh="1, 2"/>  
        </video>  
       </clip>  
       <transition name="Cross Dissolve" offset="313200/90000s" duration="1s">  
        <filter-video ref="r4" name="Cross Dissolve">  
         <param name="Look" key="1" value="11 (Video)"/>  
         <param name="Amount" key="2" value="50"/>  
         <param name="Ease" key="50" value="2 (In & Out)"/>  
         <param name="Ease Amount" key="51" value="0"/>  
        </filter-video>  
        <filter-audio ref="r5" name="Audio Crossfade"/>  
       </transition>  
      </spine>  
     </clip>  
     <transition name="Cross Dissolve" offset="4s" duration="1s">  
      <filter-video ref="r4" name="Cross Dissolve">  
       <param name="Look" key="1" value="11 (Video)"/>  
       <param name="Amount" key="2" value="50"/>  
       <param name="Ease" key="50" value="2 (In & Out)"/>  
       <param name="Ease Amount" key="51" value="0"/>  
      </filter-video>  
      <filter-audio ref="r5" name="Audio Crossfade"/>  
     </transition>  
    </spine>  
 
I'm thinking that using NSXMLParser would be the best bet, so I've one up like this:
 
NSXMLParser *new_parser = [[NSXMLParser alloc] initWithData:[NSData dataWithBytes:[[theXMLElement stringValue] UTF8String] length:[theXMLElement stringValue].length]];  
[new_parser setDelegate:self];  
BOOL parse_success = [new_parser parse];
  
 
But it fails as the -stringValue of the element returns a zero-length string (checked with a NSLog output). So how should I setup to parse just the above element (or similar) of a larger NSXMLDocument?

I should have used -XMLString to get a valid string for the parser. I'd seen -stringValue somewhere and it had become stuck in my head.

Related

combine UITextFields input into one UITtextField

Im new to xcode and objective c. I have asked this question three times and still can't find a good method or answer. I have several uitextfields that accept user input and adds it to the combinedtextField in order of IBAction used.ie user inputs big in one field,bad in the next one and boy in the third and the result is big bad boy in the combinedtextField.
-(IBAction)addtextField1: (id)sender
{
combinedtextField.text = [NSMutableString stringWithFormat:#"%# %#",
combinedtextField.text,textField1.text];
}
-(IBAction)addtextField2: (id)sender
{
combinedtextField.text = [NSMutableString stringWithFormat:#"%# %#",
combinedtextField.text, textField2.text];
}
-(IBAction)addtextField3:(id)sender
{
combinedtextField.text = [NSMutableString stringWithFormat:#"%# %#",
combinedtextField.text,textField3.text];
}
Now this is where it gets interesting.I need to be able to remove the selected text from the combinedtextField.
-(IBAction)removetextField1:(id)sender
{
//////////????????????////////////////
}
-(IBAction)removetextField2: (id)sender
{
//////////????????????////////////////
}
-(IBAction)removetextField3: (id)sender
{
//////////????????????////////////////
}
If I tap the removetextField2 button it would remove the corresponding text(bad) from the combinedtextField and then it would read (big boy)
Ive looked into nsarrays,nsdictionarys and other methods and have got no where.
Need some way of possibly tagging the input and removing it that way. Example code would be great and very much appreciated.
You've left out some important details about your app, so I'm making some guesses about how it should work.
Perhaps what you should do is keep a mutable array of all of the fragments that have been added to the combined string:
#implementation MyViewController {
    NSMutableArray *fragments_;
}
- (void)viewDidLoad {
[super viewDidLoad];
fragments_ = [[NSMutableArray alloc] init];
}
When one of the add buttons is tapped, you append the corresponding field's text to the array and recompute the combined string:
- (IBAction)addTextField1:(id)sender {
[fragments_ addObject:textField1.text];
[self updateCombinedTextField];
}
- (void)updateCombinedTextField {
combinedTextField.text = [fragments componentsJoinedByString:#" "];
}
When one of the remove buttons is tapped, you try to remove the corresponding field's text from the fragments array and recompute the combined string:
- (IBAction)removeTextField1:(id)sender {
[fragments_ removeObject:textField1.text];
[self updateCombinedTextField];
}
That will remove all occurrences of field 1's text from the fragments array. If you just want to remove one instance, you will need to use indexOfObject: (or one of its variants) followed by removeObjectAtIndex:.
You can't do it in a very trivial way (without anything to add, just 1stroke magic function). But, there's the easy way, which i'd possible gone for.
If you don't need to do it a lot of times, and / or the text is quite small (not like a 500 pages book), then:
Create a boolean array named mark, and mark[i] should mark the i'th text field as 'added'. Then, create a function named reloadCombinedTextField, which creates it again, depended of the mark array. (if mark[i] == true, then we add a textfield's text, otherwise not)
Then, just mark or unmark the needed text fields in every function and call the reload function in the end of every call.
Altho, there is another way, but it can be wrong in situations where your text fields have the same text. The thing is, you just search in your combined text field the text from selected text field (for example, with [NSString rangeOfString] method) and remove it.
If you are going to do it often and the text is really big, then it goes much more complicated. But i'm quite sure, that you won't do this on iOS.

Better CoffeeScript syntax for jQuery parameters

I have this code for making a post request, sending some data, and logging the return value
$.post '/saveletter', {start: {x: startX, y:startY}, letter: currentLetter, unitVectors: letter.unitVectorsJson(), timeVectors: letter.timeVectorsJson()}, (data) =>
console.log data
I want to split the long parameter object into several lines, for better readability, but can't figure out the syntax that will work.
To make your code more readable, you can use the following (fiddle and compiled result):
$.post '/saveletter',
    start:
        x: startX
        y: startY
    letter: currentLetter
    unitVectors: letter.unitVectorsJson()
    timeVectors: letter.timeVectorsJson()
, (data) =>
  console.log data​​
In Coffeescript, { and } may be omitted from the object literal. And commas may be exchanged for newlines (within an object literal, not between arguments).
The following is also valid, but might be less readable (ie not obvious at the first glance):
start: x: startX, y: startY

Subscript and Superscripts in CDATA of an xml file. Using UILabel to display the parsed XML contents

I need to display subscripts and superscripts (only arabic numerals) within a UILabel. The data is taken from an XML file. Here is the snippet of XML file:
<text><![CDATA[Hello World X\u00B2 World Hello]]></text>
Its supposed to display X2 (2 as superscript). When I read the string from the NSXMLParser and display it in the UILabel, it displays it as X\u00B2. Any ideas on how to make it work?
I think you can do something like this, assuming the CDATA contents have been read into an NSString and passed into this function:
-(NSString *)removeUnicodeEscapes:(NSString *)stringWithUnicodeEscapes {
unichar codeValue;
NSMutableString *result = [stringWithUnicodeEscapes mutableCopy];
NSRange unicodeLocation = [result rangeOfString:#"\\u"];
while (unicodeLocation.location != NSNotFound) {
// Get the 4-character hex code
NSRange charCodeRange = NSMakeRange(unicodeLocation.location + 2, 4);
NSString *charCode = [result substringWithRange:charCodeRange];
[[NSScanner scannerWithString:charCode] scanHexInt:&codeValue];
// Convert it to an NSString and replace in original string
NSString *unicodeChar = [NSString stringWithFormat:%C", codeValue];
NSRange replacementRange = NSMakeRange(unicodeLocation.location, 6);
[result replaceCharactersInRange:replacementRange withString:unicodeChar];
unicodeLocation = [result rangeOfString:#"\\u"];
}
return result;
}
I haven't had a chance to try this out, but I think the basic approach would work
\u00B2 is not any sort of XML encoding for characters. Apparently your data source has defined their own encoding scheme (which, frankly, is pretty stupid as XML is capable of encoding these directly, using entities outside of CDATA blocks).
In any case, you'll have to write your own parser that handles \u#### and converts that to the correct character.
I asked the question to my colleague and he gave me a nice and simple workaround. Am describing it here, in case others also get stuck at this.
Firstly goto this link. It has a list of all subscripts and superscripts. For example, in my case, I clicked on "superscript 0". In the following HTML page detailing "superscript 0", goto "Java Data" section and copy the "⁰". You can either place this directly in XML or write a simple regex in obj-c to replace \u00B2 with "⁰". And you will get nice X⁰. Do the same fro anyother superscript or subscript that you might want to display.

NSMutableDictionary representation for JSON

I have one genuine question which I am facing at this point and I am sure someone might be able to help me.
I have a JSON Post which looks like:
{
"CustomerAccount":{
"CustomerUID":"String content",
"UserName":"String content",
"Password":"String content",
"OldPassword":"String content",
"Email":"String content",
"QuestionUID":2147483647,
"QuestionAnswer":"String content",
"EAlerts":true
}
}
Now I have a dictionay which set's value of CustomerUID, UserName, etc.. Now if I want to bind a upper level to bind all that to CustomerAccount and send as my JSONRepresentation, is there any easier way than actually creating a new dictionary and setting a value of key "CustomerAccount" in this example? I am sure there might be a better way of doing that.
Thanks.
Not entirely sure I follow, but is this what you want maybe:
NSDictionary *dictA = <dictionary_with_customeruid_etc>;
NSDictionary *customerAccountDict = [NSDictionary dictionaryWithObjectsAndKeys:dictA, #"CustomerAccount", nil];
But I'm not sure I follow your question entirely so maybe you want something else. Please let us know a bit more about what you're trying to do.
I don't really understand your question but ill give it a try.
You can easily parse the JSON string to a NSDictionary using JSONKit https://github.com/johnezang/JSONKit
JSONKit is a very fast and lightweight library and you can parse the string and get the wanted value like this:
NSDictionary *dict = [jsonString objectFromJSONString];
NSString *value = [dict valueForKey:#"key"];
To actually set a value in your JSON string you should use rangeOfString: .location to get the range if the existing value then replaceOccurenciesOfString:[jsonString substringWithRange:NSMakeRange(loc,len)] withString:VALUE.

iPhone SDK: XML mystery, after adding child nodeforXPath returns nothing (found a hacky solution)

I have a big mystery here,
I have a Gdataxml document property:
GDataXMLDocument *doc;
I'm adding a new element to doc, interestingly, this method below looks perfect for other elements but not for the element I just added:
GDataXMLElement *newValueDefElement = [GDataXMLNode elementWithName:#"valuedefinition"];
[variableElement addChild:newValueDefElement];
and now when I query:
NSString *path = [NSString stringWithFormat:#"//inferenceresponse/state/variable[pageId=%d]/valuedefinition",pageID];
NSArray *valueElement = [self.doc nodesForXPath:path error:nil];
Now array comes with zero objects! new added element NOT found! but I can see it in debug as xml string, how on earth it can not find something which I can see it is there on the log? it is a cache problem or a namespace problem or a bug in GDataXML? again..Problem is adding a new child and it is somehow not updated in the doc, but I can get the other elements under same root when use the same Xpath query standard
in NSlog I can see that the new element is added to doc.
NSData *xmlData2 = self.doc.XMLData;
NSString *s= [[[NSString alloc] initWithBytes:[xmlData2 bytes] length:[xmlData2 length] encoding:NSUTF8StringEncoding] autorelease];
NSLog(s);
Also How can self.doc.XMLData give something different than [self.doc nodesForXPath]? so it fools me to thing my doc is ok but maybe I corrupted the doc or a wrong namespace while adding removing some elements in a previous method?
my xml starts like this:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<inferenceresponse xmlns="">
<state goalreached="false">
..
..
Update
I just found a (hacky) solution; when I convert "doc" to NSData with "doc.XMLData" and then again convert back to doc, then it works! but this should not be real solution, that's lame to do that conversion back and forth to get a correct document object. What is the problem here? I guess it can not fix the namespaces for new child.
Your problem is here:
<inferenceresponse xmlns="">
The empty namespace attribute is obviously confusing the libxml XPath evaluation. If you step through GDataXMLNode's nodesForXPath:namespaces:error:, xmlXPathEval indeed returns an empty nodes set.
If you have control over the XML generation, I've got correct XPath results removing the empty attribute.
<inferenceresponse>
If modifying the server response is too hard, you can edit GDataXMLNode.m:
Find the method fixQualifiedNamesForNode:graftingToTreeNode: in GDataXMLNode implementation and replace the line
if (foundNS != NULL) {
// we found a namespace, so fix the ns pointer and the local name
with
if (foundNS != NULL && foundNS->href != NULL && strlen((char *)foundNS->href) != 0) {
// we found a namespace, so fix the ns pointer and the local name