Skip to content

Commit

Permalink
Merge pull request #2302 from vishalduggal/timob-9084
Browse files Browse the repository at this point in the history
[TIMOB-9084] iOS: XML xmlns:xmlns definition
  • Loading branch information
Max Stepanov committed Jun 2, 2012
2 parents 6cd8aa5 + ccd5786 commit 42ac869
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 73 deletions.
2 changes: 2 additions & 0 deletions iphone/Classes/GDataXMLNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ typedef NSUInteger GDataXMLNodeKind;
- (void)addAttribute:(GDataXMLNode *)attribute;

- (NSString *)resolvePrefixForNamespaceURI:(NSString *)namespaceURI;
//Need to make this visible. Used in appendChild of ElementProxy
+ (void)fixUpNamespacesForNode:(xmlNodePtr)nodeToFix graftingToTreeNode:(xmlNodePtr)graftPointNode;

@end

Expand Down
5 changes: 5 additions & 0 deletions iphone/Classes/TIDOMCharacterDataProxy.m
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ -(void)setData:(NSString *)data
[node setStringValue:data];
}

-(void)setNodeValue:(NSString *)data
{
[self setData:data];
}

-(NSNumber *)length
{
xmlNodePtr realNode = [node XMLNode];
Expand Down
108 changes: 47 additions & 61 deletions iphone/Classes/TIDOMDOMImplementationProxy.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#import "TIDOMDOMImplementationProxy.h"
#import "TIDOMDocumentTypeProxy.h"
#import "TiDOMDocumentProxy.h"
#import "TiDOMValidator.h"
#import "TiUtils.h"


Expand Down Expand Up @@ -63,77 +64,62 @@ -(id)createDocumentType:(id)args

-(id)createDocument:(id)args
{
ENSURE_ARG_COUNT(args, 3);
NSObject* obj1;
NSObject* obj2;
NSObject* obj3;
NSString* theNsURI;
NSString* qualifiedName;
TIDOMDocumentTypeProxy* docType;
ENSURE_ARG_COUNT(args, 3);
NSString* theURI = [args objectAtIndex:0];
NSString* qualifiedName = [args objectAtIndex:1];
TIDOMDocumentTypeProxy* docType = [args objectAtIndex:2];

ENSURE_ARG_OR_NIL_AT_INDEX(obj1,args,0,NSObject);
ENSURE_ARG_OR_NIL_AT_INDEX(obj2,args,1,NSObject);
ENSURE_ARG_OR_NIL_AT_INDEX(obj3,args,2,NSObject);

theNsURI = [TiUtils stringValue:obj1];
qualifiedName = [TiUtils stringValue:obj2];

if (qualifiedName == nil)
{
[self throwException:@"Could not create root element with null qualified name" subreason:nil location:CODELOCATION];
return [NSNull null];
}
ENSURE_STRING_OR_NIL(theURI);
ENSURE_STRING(qualifiedName);
ENSURE_TYPE_OR_NIL(docType, TIDOMDocumentTypeProxy);

//Validate the parameters
NSString *error = nil;
NSString *suberror = nil;

if ([obj3 isKindOfClass:[NSNull class]])
{
docType = nil;
}
else if ( [obj3 isKindOfClass:[TIDOMDocumentTypeProxy class]] )
{
docType = (TIDOMDocumentTypeProxy*)obj3;
[TiDOMNodeProxy validateElementParameters:qualifiedName withUri:theURI reason:&error subreason:&suberror];

if (error != nil) {
[self throwException:error subreason:suberror location:CODELOCATION];
}
else
{
[self throwException:@"Invalid argument passed for docType" subreason:nil location:CODELOCATION];
return [NSNull null];
}

xmlChar *pre = NULL;
xmlChar *href = NULL;
if(theNsURI != nil)
href = (xmlChar*)[theNsURI UTF8String];
NSString* prefix = [GDataXMLNode prefixForName:qualifiedName];
NSString* localName = [GDataXMLNode localNameForName:qualifiedName];

if ([prefix length] > 0)
{
pre = (xmlChar*)[prefix UTF8String];
}
xmlNsPtr theNewNs = xmlNewNs(NULL, // parent node

//Create the new NS pointer
xmlChar *pre = NULL;
xmlChar *href = NULL;
if(theURI != nil) {
href = (xmlChar*)[theURI UTF8String];
}
if ([prefix length] > 0) {
pre = (xmlChar*) [prefix UTF8String];
}
xmlNsPtr theNewNs = xmlNewNs(NULL, // parent node
href, pre);
xmlNodePtr rootPtr = xmlNewNode(theNewNs, (xmlChar*)[localName UTF8String]);
xmlDocPtr doc = xmlNewDoc(NULL);
xmlDocSetRootElement(doc, rootPtr);
GDataXMLDocument * theDocument = [[[GDataXMLDocument alloc]initWithDocument:doc]autorelease];

if (docType != nil)
{
GDataXMLNode *docTypeNode = [docType node];
xmlNodePtr ret = xmlAddChild((xmlNodePtr)doc, [docTypeNode XMLNode]);
if (ret != NULL)
{
//Now it is part of the tree so switch flag to ensur it gets freed when doc is released
[docTypeNode setShouldFreeXMLNode:NO];
}
}
id context = ([self executionContext]==nil)?[self pageContext]:[self executionContext];
TiDOMDocumentProxy * result = [[[TiDOMDocumentProxy alloc] _initWithPageContext:context] autorelease];
[result setNode:[theDocument rootElement]];
[result setDocument:theDocument];
[TiDOMNodeProxy setNode:result forXMLNode:(xmlNodePtr)doc];
return result;
//Create the doc node with root element
xmlNodePtr rootPtr = xmlNewNode(theNewNs, (xmlChar*)[localName UTF8String]);
rootPtr->nsDef = theNewNs;
xmlDocPtr doc = xmlNewDoc(NULL);
xmlDocSetRootElement(doc, rootPtr);

if (docType != nil) {
GDataXMLNode *docTypeNode = [docType node];
xmlNodePtr ret = xmlAddChild((xmlNodePtr)doc, [docTypeNode XMLNode]);
if (ret != NULL) {
//Now it is part of the tree so switch flag to ensur it gets freed when doc is released
[docTypeNode setShouldFreeXMLNode:NO];
}
}

GDataXMLDocument * theDocument = [[[GDataXMLDocument alloc]initWithDocument:doc]autorelease];
id context = ([self executionContext]==nil)?[self pageContext]:[self executionContext];
TiDOMDocumentProxy * result = [[[TiDOMDocumentProxy alloc] _initWithPageContext:context] autorelease];
[result setNode:[theDocument rootElement]];
[result setDocument:theDocument];
[TiDOMNodeProxy setNode:result forXMLNode:(xmlNodePtr)doc];
return result;
}

@end
Expand Down
6 changes: 4 additions & 2 deletions iphone/Classes/TiDOMDocumentProxy.m
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ -(id)createAttributeNS:(id)args
NSString *error = nil;
NSString *suberror = nil;

[self validateAttributeParameters:tagName withUri:theURI reason:&error subreason:&suberror];
[TiDOMNodeProxy validateAttributeParameters:tagName withUri:theURI reason:&error subreason:&suberror];
if (error != nil) {
[self throwException:error subreason:suberror location:CODELOCATION];
}
Expand Down Expand Up @@ -225,7 +225,7 @@ -(id)createElementNS:(id)args

NSString *error = nil;
NSString *suberror = nil;
[self validateElementParameters:tagName withUri:theURI reason:&error subreason:&suberror];
[TiDOMNodeProxy validateElementParameters:tagName withUri:theURI reason:&error subreason:&suberror];
if (error != nil) {
[self throwException:error subreason:suberror location:CODELOCATION];
}
Expand Down Expand Up @@ -255,6 +255,8 @@ -(id)createElementNS:(id)args
xmlNsPtr theNewNs = xmlNewNs(NULL, // parent node
href, pre);
[resultElement XMLNode]->ns = theNewNs;
//Assume that this NS is defined on this node. Will be fixed later when added to tree
[resultElement XMLNode]->nsDef = theNewNs;
[result setDocument:[self document]];
[result setElement:resultElement];
[TiDOMNodeProxy setNode:result forXMLNode:[resultElement XMLNode]];
Expand Down
17 changes: 16 additions & 1 deletion iphone/Classes/TiDOMElementProxy.m
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ -(void)setAttributeNS:(id)args
NSString *error = nil;
NSString *suberror = nil;

[self validateAttributeParameters:name withUri:theURI reason:&error subreason:&suberror];
[TiDOMNodeProxy validateAttributeParameters:name withUri:theURI reason:&error subreason:&suberror];
if (error != nil) {
[self throwException:error subreason:suberror location:CODELOCATION];
}
Expand Down Expand Up @@ -240,6 +240,7 @@ -(void)setAttributeNS:(id)args
xmlNsPtr theNewNs = xmlNewNs(NULL, // parent node
href, pre);
xmlNewNsProp(curNode, theNewNs, (xmlChar*)[localName UTF8String], (xmlChar*)[val UTF8String]);
[GDataXMLElement fixUpNamespacesForNode:curNode graftingToTreeNode:curNode];
}
}

Expand Down Expand Up @@ -369,6 +370,11 @@ -(id)setAttributeNode:(id)args
{
ENSURE_SINGLE_ARG(args, TiDOMAttrProxy);
TiDOMAttrProxy* attProxy = (TiDOMAttrProxy*)args;

if ([[attProxy node] URI] != nil) {
return [self setAttributeNodeNS:args];
}

NSString* name = [[attProxy node]name];

TiDOMAttrProxy* result = nil;
Expand Down Expand Up @@ -486,6 +492,7 @@ -(id)setAttributeNodeNS:(id)args
NSString* val = [[attProxy node] stringValue];

xmlNewNsProp(curNode, theNewNs, (xmlChar*)[localName UTF8String], (xmlChar*)[val UTF8String]);
[GDataXMLElement fixUpNamespacesForNode:curNode graftingToTreeNode:curNode];
attributeNode = [element attributeForLocalName:localName URI:theURI];
[attProxy setNode:attributeNode];
[attProxy setAttribute:[attributeNode name] value:[attributeNode stringValue] owner:element];
Expand Down Expand Up @@ -691,12 +698,20 @@ -(id)appendChild:(id)args
{
ENSURE_SINGLE_ARG(args, TiDOMNodeProxy);
TiDOMNodeProxy * newChild = (TiDOMNodeProxy*)args;
if ([newChild document] != [self document]) {
[self throwException:@"mismatched documents" subreason:nil location:CODELOCATION];
return [NSNull null];
}
BOOL needsReconciliateNS = [newChild isKindOfClass:[TiDOMElementProxy class]];
xmlNodePtr oldNodePtr = [[newChild node] XMLNode];
xmlNodePtr parent = [element XMLNode];
xmlNodePtr resultPtr = xmlAddChild(parent, oldNodePtr);

if (resultPtr != NULL) {
[[self node] releaseCachedValues];
if (needsReconciliateNS) {
[GDataXMLElement fixUpNamespacesForNode:resultPtr graftingToTreeNode:parent];
}
//Child added successfully
if (resultPtr == oldNodePtr) {
//Child pointer not modified
Expand Down
4 changes: 2 additions & 2 deletions iphone/Classes/TiDOMNodeProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@
+(id)nodeForXMLNode:(xmlNodePtr) nodePtr;
+(void)setNode:(id)node forXMLNode:(xmlNodePtr) nodePtr;
+(void)removeNodeForXMLNode:(xmlNodePtr)nodePtr;
+(void)validateAttributeParameters:(NSString*)tagName withUri:(NSString*)theURI reason:(NSString**)error subreason:(NSString**)suberror;
+(void)validateElementParameters:(NSString*)tagName withUri:(NSString*)theURI reason:(NSString**)error subreason:(NSString**)suberror;

-(id)makeNodeListProxyFromArray:(NSArray*)nodes context:(id<TiEvaluator>)context;
-(void)validateAttributeParameters:(NSString*)tagName withUri:(NSString*)theURI reason:(NSString**)error subreason:(NSString**)suberror;
-(void)validateElementParameters:(NSString*)tagName withUri:(NSString*)theURI reason:(NSString**)error subreason:(NSString**)suberror;

@property(nonatomic,readonly) id nodeName;
@property(nonatomic,copy,readwrite) id nodeValue;
Expand Down
7 changes: 3 additions & 4 deletions iphone/Classes/TiDOMNodeProxy.m
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ -(id)makeNodeListProxyFromArray:(NSArray*)nodes context:(id<TiEvaluator>)context

}

-(void)validateAttributeParameters:(NSString*)tagName withUri:(NSString*)theURI reason:(NSString**)error subreason:(NSString**)suberror
+(void)validateAttributeParameters:(NSString*)tagName withUri:(NSString*)theURI reason:(NSString**)error subreason:(NSString**)suberror
{
NSString* prefix = [GDataXMLNode prefixForName:tagName];
NSString* localName = [GDataXMLNode localNameForName:tagName];
Expand Down Expand Up @@ -179,7 +179,7 @@ -(void)validateAttributeParameters:(NSString*)tagName withUri:(NSString*)theURI
}
}

-(void)validateElementParameters:(NSString*)tagName withUri:(NSString*)theURI reason:(NSString**)error subreason:(NSString**)suberror
+(void)validateElementParameters:(NSString*)tagName withUri:(NSString*)theURI reason:(NSString**)error subreason:(NSString**)suberror
{
NSString* prefix = [GDataXMLNode prefixForName:tagName];
NSString* localName = [GDataXMLNode localNameForName:tagName];
Expand Down Expand Up @@ -372,8 +372,7 @@ -(id)nodeValue

-(void)setNodeValue:(NSString *)data
{
ENSURE_TYPE(data, NSString);
[node setStringValue:data];
[self throwException:[NSString stringWithFormat:@"Setting NodeValue not supported for %d type of Node",[self nodeType]] subreason:nil location:CODELOCATION];
}

- (id)textContent
Expand Down
5 changes: 5 additions & 0 deletions iphone/Classes/TiDOMPIProxy.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ -(void)setData:(NSString *)data
[node setStringValue:data];
}

-(void)setNodeValue:(NSString *)data
{
[self setData:data];
}

-(NSString*)target
{
return [node name];
Expand Down
66 changes: 63 additions & 3 deletions iphone/Classes/XMLModule.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,72 @@ -(id)parseString:(id)arg

-(id)serializeToString:(id)arg
{
ENSURE_SINGLE_ARG(arg,TiDOMNodeProxy);
ENSURE_SINGLE_ARG(arg,TiDOMNodeProxy);

TiDOMNodeProxy *proxy = (TiDOMNodeProxy *)arg;
return [proxy XMLString];
TiDOMNodeProxy *proxy = (TiDOMNodeProxy *)arg;
NSString* xmlString = [proxy XMLString];
if ([xmlString length] == 0) {
return xmlString;
}

//Strip out all the xmlns:xmlns="http://www.w3.org/2000/xmlns/" definitions
NSString* strippedString = [xmlString stringByReplacingOccurrencesOfString:@" xmlns:xmlns=\"http://www.w3.org/2000/xmlns/\"" withString:@""];

//Clean out duplicate namespace definitions
NSString* cleanString = [self cleanDuplicateNS:strippedString];

return cleanString;
}

/**
IOS does not have a proper transformer like java. (javax.xml.transform.Transformer)
It is perfectly valid to have an element with a namespace and an attribute whose values match the namespace
Eg:
var doc = Ti.XML.parseString('<a/>');
var feed = doc.implementation.createDocument('http://www.test.org/myns', 'myns:feed', null);
feed.documentElement.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:myns', 'http://www.test.org/myns');
When you print out feed it will print out the NS myns twice. This method cleans out the duplicate NS definitions
*/
-(NSString*) cleanDuplicateNS:(NSString*)xmlString
{
NSRange searchRange = NSMakeRange(0, [xmlString length]);

NSRange result = [xmlString rangeOfString:@" xmlns" options:0 range:searchRange];
while (result.location != NSNotFound) {
searchRange.location = result.location+result.length;
searchRange.length = [xmlString length] - (searchRange.location);

//Search for end of element
NSRange endOfElement = [xmlString rangeOfString:@">" options:0 range:searchRange];
//Search for end of NS definition
NSRange endOfNS = [xmlString rangeOfString:@" " options:0 range:searchRange];
if (endOfNS.location < endOfElement.location) {
//Get the actual xmlns definition
NSRange subStringRange = NSMakeRange(result.location, endOfNS.location - result.location);
NSString* subString = [xmlString substringWithRange:subStringRange];

//Set up a search range
subStringRange.location = endOfNS.location;
subStringRange.length = endOfElement.location - endOfNS.location;
xmlString = [xmlString stringByReplacingOccurrencesOfString:subString withString:@"" options:0 range:subStringRange];

//Update search range
searchRange.location = subStringRange.location+1;
searchRange.length = [xmlString length] - searchRange.location;
}
else {
//Not in this element. Update search range.
searchRange.location = endOfElement.location+1;
searchRange.length = [xmlString length] - searchRange.location;
}
result = [xmlString rangeOfString:@" xmlns" options:0 range:searchRange];
}

return xmlString;
}


@end

#endif

0 comments on commit 42ac869

Please sign in to comment.