Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TIMOB-9084] iOS: XML xmlns:xmlns definition #2302

Merged
merged 15 commits into from
Jun 2, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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