From 36b74b57662e8392533d09eebd5f2081dca148d9 Mon Sep 17 00:00:00 2001 From: iska Date: Tue, 31 Mar 2015 01:01:41 +0200 Subject: [PATCH] Add HTML fragment serialization (inner & outer HTML) https://html.spec.whatwg.org/multipage/syntax.html#serialising-html-fragments --- HTMLKit/HTMLComment.m | 7 +++++++ HTMLKit/HTMLDocumentType.m | 7 +++++++ HTMLKit/HTMLElement.m | 39 ++++++++++++++++++++++++++++++++++++++ HTMLKit/HTMLNode.h | 2 ++ HTMLKit/HTMLNode.m | 16 ++++++++++++++++ HTMLKit/HTMLText.m | 20 +++++++++++++++++++ 6 files changed, 91 insertions(+) diff --git a/HTMLKit/HTMLComment.m b/HTMLKit/HTMLComment.m index 0f5aac0..23194bc 100644 --- a/HTMLKit/HTMLComment.m +++ b/HTMLKit/HTMLComment.m @@ -38,6 +38,13 @@ return copy; } +#pragma mark - Serialization + +- (NSString *)outerHTML +{ + return [NSString stringWithFormat:@"", self.data]; +} + #pragma mark - Description - (NSString *)description diff --git a/HTMLKit/HTMLDocumentType.m b/HTMLKit/HTMLDocumentType.m index a9b20de..ce6687f 100644 --- a/HTMLKit/HTMLDocumentType.m +++ b/HTMLKit/HTMLDocumentType.m @@ -133,6 +133,13 @@ NS_INLINE BOOL nilOrEqual(id first, id second) { return copy; } +#pragma mark - Serialization + +- (NSString *)outerHTML +{ + return [NSString stringWithFormat:@"", self.name]; +} + #pragma mark - Description - (NSString *)description diff --git a/HTMLKit/HTMLElement.m b/HTMLKit/HTMLElement.m index 58fb0b6..4425dcd 100644 --- a/HTMLKit/HTMLElement.m +++ b/HTMLKit/HTMLElement.m @@ -8,6 +8,8 @@ #import "HTMLElement.h" #import "HTMLOrderedDictionary.h" +#import "NSString+HTMLKit.h" +#import "HTMLText.h" @interface HTMLElement () { @@ -96,6 +98,43 @@ return copy; } +#pragma mark - Serialization + +- (NSString *)outerHTML +{ + NSMutableString *result = [NSMutableString string]; + + [result appendFormat:@"<%@", self.tagName]; + [self.attributes enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) { + NSRange range = NSMakeRange(0, value.length); + NSMutableString *escaped = [value mutableCopy]; + [escaped replaceOccurrencesOfString:@"&" withString:@"&" options:0 range:range]; + [escaped replaceOccurrencesOfString:@"\00A0" withString:@" " options:0 range:range]; + [escaped replaceOccurrencesOfString:@"\"" withString:@""" options:0 range:range]; + + [result appendFormat:@" %@=\"%@\"", key, escaped]; + }]; + + [result appendString:@">"]; + + if ([self.tagName isEqualToAny:@"area", @"base", @"basefont", @"bgsound", @"br", @"col", @"embed", + @"frame", @"hr", @"img", @"input", @"keygen", @"link", @"menuitem", @"meta", @"param", @"source", + @"track", @"wbr", nil]) { + return result; + } + + if ([self.tagName isEqualToAny:@"pre", @"textarea", @"listing", nil] && self.firstChiledNode.type == HTMLNodeText) { + HTMLText *textNode = (HTMLText *)self.firstChiledNode; + if ([textNode.data hasPrefix:@"\n"]) { + [result appendString:@"\n"]; + } + } + [result appendString:self.innerHTML]; + [result appendFormat:@"", self.tagName]; + + return result; +} + #pragma mark - Description - (NSString *)description diff --git a/HTMLKit/HTMLNode.h b/HTMLKit/HTMLNode.h index dddbd4f..45f2950 100644 --- a/HTMLKit/HTMLNode.h +++ b/HTMLKit/HTMLNode.h @@ -79,6 +79,8 @@ typedef NS_ENUM(short, HTMLNodeType) - (NSEnumerator *)treeEnumerator; - (NSEnumerator *)reverseTreeEnumerator; +- (NSString *)outerHTML; +- (NSString *)innerHTML; - (NSString *)treeDescription; @end diff --git a/HTMLKit/HTMLNode.m b/HTMLKit/HTMLNode.m index 5b790a4..94fd4d1 100644 --- a/HTMLKit/HTMLNode.m +++ b/HTMLKit/HTMLNode.m @@ -8,7 +8,10 @@ #import "HTMLNode.h" #import "HTMLDocument.h" +#import "HTMLDocumentType.h" #import "HTMLElement.h" +#import "HTMLText.h" +#import "HTMLComment.h" #import "HTMLKitExceptions.h" #import "HTMLNodeTreeEnumerator.h" @@ -353,6 +356,19 @@ NS_INLINE void CheckInvalidCombination(HTMLNode *parent, HTMLNode *node, NSStrin return copy; } +#pragma mark - Serialization + +- (NSString *)outerHTML +{ + [self doesNotRecognizeSelector:_cmd]; + return nil; +} + +- (NSString *)innerHTML +{ + return [[_childNodes.array valueForKey:@"outerHTML"] componentsJoinedByString:@""]; +} + #pragma mark - Description - (NSString *)treeDescription diff --git a/HTMLKit/HTMLText.m b/HTMLKit/HTMLText.m index 10ae1dd..36bb035 100644 --- a/HTMLKit/HTMLText.m +++ b/HTMLKit/HTMLText.m @@ -7,6 +7,8 @@ // #import "HTMLText.h" +#import "HTMLElement.h" +#import "NSString+HTMLKit.h" @implementation HTMLText @@ -48,6 +50,24 @@ return copy; } +#pragma mark - Serialization + +- (NSString *)outerHTML +{ + if ([self.parentElement.tagName isEqualToAny:@"style", @"script", @"xmp", @"iframe", @"noembed", @"noframes", + @"plaintext", @"noscript", nil]) { + return self.data; + } else { + NSRange range = NSMakeRange(0, self.data.length); + NSMutableString *escaped = [self.data mutableCopy]; + [escaped replaceOccurrencesOfString:@"&" withString:@"&" options:0 range:range]; + [escaped replaceOccurrencesOfString:@"\00A0" withString:@" " options:0 range:range]; + [escaped replaceOccurrencesOfString:@"<" withString:@"<" options:0 range:range]; + [escaped replaceOccurrencesOfString:@">" withString:@">" options:0 range:range]; + return escaped; + } +} + #pragma mark - Description - (NSString *)description