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