Skip to content

Commit 00d332c

Browse files
Merge pull request #396 from karlseguin/xmlserializer
Add HTML encoding to text node and HTML attribute values
2 parents 4c8c0f8 + 5497813 commit 00d332c

File tree

1 file changed

+78
-10
lines changed

1 file changed

+78
-10
lines changed

src/browser/dump.zig

Lines changed: 78 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ pub fn writeNode(node: *parser.Node, writer: anytype) anyerror!void {
4646
try writer.writeAll(" ");
4747
try writer.writeAll(try parser.attributeGetName(attr));
4848
try writer.writeAll("=\"");
49-
try writer.writeAll(try parser.attributeGetValue(attr) orelse "");
49+
const attribute_value = try parser.attributeGetValue(attr) orelse "";
50+
try writeEscapedAttributeValue(writer, attribute_value);
5051
try writer.writeAll("\"");
5152
i += 1;
5253
}
@@ -67,7 +68,7 @@ pub fn writeNode(node: *parser.Node, writer: anytype) anyerror!void {
6768
},
6869
.text => {
6970
const v = try parser.nodeValue(node) orelse return;
70-
try writer.writeAll(v);
71+
try writeEscapedTextNode(writer, v);
7172
},
7273
.cdata_section => {
7374
const v = try parser.nodeValue(node) orelse return;
@@ -119,18 +120,85 @@ fn isVoid(elem: *parser.Element) !bool {
119120
};
120121
}
121122

123+
fn writeEscapedTextNode(writer: anytype, value: []const u8) !void {
124+
var v = value;
125+
while (v.len > 0) {
126+
const index = std.mem.indexOfAnyPos(u8, v, 0, &.{'&', '<', '>'}) orelse {
127+
return writer.writeAll(v);
128+
};
129+
try writer.writeAll(v[0..index]);
130+
switch (v[index]) {
131+
'&' => try writer.writeAll("&amp;"),
132+
'<' => try writer.writeAll("&lt;"),
133+
'>' => try writer.writeAll("&gt;"),
134+
else => unreachable,
135+
}
136+
v = v[index+1..];
137+
}
138+
}
139+
140+
fn writeEscapedAttributeValue(writer: anytype, value: []const u8) !void {
141+
var v = value;
142+
while (v.len > 0) {
143+
const index = std.mem.indexOfAnyPos(u8, v, 0, &.{'&', '<', '>', '"'}) orelse {
144+
return writer.writeAll(v);
145+
};
146+
try writer.writeAll(v[0..index]);
147+
switch (v[index]) {
148+
'&' => try writer.writeAll("&amp;"),
149+
'<' => try writer.writeAll("&lt;"),
150+
'>' => try writer.writeAll("&gt;"),
151+
'"' => try writer.writeAll("&quot;"),
152+
else => unreachable,
153+
}
154+
v = v[index+1..];
155+
}
156+
}
157+
158+
const testing = std.testing;
122159
test "dump.writeHTML" {
123-
const out = try std.fs.openFileAbsolute("/dev/null", .{ .mode = .write_only });
124-
defer out.close();
160+
try testWriteHTML(
161+
"<div id=\"content\">Over 9000!</div>",
162+
"<div id=\"content\">Over 9000!</div>"
163+
);
164+
165+
try testWriteHTML(
166+
"<root><!-- a comment --></root>",
167+
"<root><!-- a comment --></root>"
168+
);
169+
170+
try testWriteHTML(
171+
"<p>&lt; &gt; &amp;</p>",
172+
"<p>&lt; &gt; &amp;</p>"
173+
);
174+
175+
try testWriteHTML(
176+
"<p id=\"&quot;&gt;&lt;&amp;&quot;''\">wat?</p>",
177+
"<p id='\">&lt;&amp;&quot;&#39;&apos;'>wat?</p>"
178+
);
179+
180+
try testWriteFullHTML(
181+
\\<!DOCTYPE html>
182+
\\<html><head><title>It's over what?</title><meta name="a" value="b">
183+
\\</head><body>9000</body></html>
184+
\\
185+
,
186+
"<html><title>It's over what?</title><meta name=a value=\"b\">\n<body>9000"
187+
);
188+
}
125189

126-
const file = try std.fs.cwd().openFile("test.html", .{});
127-
defer file.close();
190+
fn testWriteHTML(comptime expected: []const u8, src: []const u8) !void {
191+
return testWriteFullHTML("<!DOCTYPE html>\n<html><head></head><body>" ++ expected ++ "</body></html>\n", src);
192+
}
128193

129-
const doc_html = try parser.documentHTMLParse(file.reader(), "UTF-8");
130-
// ignore close error
194+
fn testWriteFullHTML(comptime expected: []const u8, src: []const u8) !void {
195+
var buf = std.ArrayListUnmanaged(u8){};
196+
defer buf.deinit(testing.allocator);
197+
198+
const doc_html = try parser.documentHTMLParseFromStr(src);
131199
defer parser.documentHTMLClose(doc_html) catch {};
132200

133201
const doc = parser.documentHTMLToDocument(doc_html);
134-
135-
try writeHTML(doc, out);
202+
try writeHTML(doc, buf.writer(testing.allocator));
203+
try testing.expectEqualStrings(expected, buf.items);
136204
}

0 commit comments

Comments
 (0)