xmlserializer for doctype

This commit is contained in:
sjorsdonkers
2025-05-28 12:29:47 +02:00
committed by Sjors
parent 527579aef4
commit e799fcd48a
2 changed files with 40 additions and 5 deletions

View File

@@ -28,6 +28,32 @@ pub fn writeHTML(doc: *parser.Document, writer: anytype) !void {
try writer.writeAll("\n"); try writer.writeAll("\n");
} }
// Spec: https://www.w3.org/TR/xml/#sec-prolog-dtd
pub fn writeDocType(doc_type: *parser.DocumentType, writer: anytype) !void {
try writer.writeAll("<!DOCTYPE ");
try writer.writeAll(try parser.documentTypeGetName(doc_type));
const public_id = try parser.documentTypeGetPublicId(doc_type);
const system_id = try parser.documentTypeGetSystemId(doc_type);
if (public_id.len != 0 and system_id.len != 0) {
try writer.writeAll(" PUBLIC \"");
try writeEscapedAttributeValue(writer, public_id);
try writer.writeAll("\" \"");
try writeEscapedAttributeValue(writer, system_id);
try writer.writeAll("\"");
} else if (public_id.len != 0) {
try writer.writeAll(" PUBLIC \"");
try writeEscapedAttributeValue(writer, public_id);
try writer.writeAll("\"");
} else if (system_id.len != 0) {
try writer.writeAll(" SYSTEM \"");
try writeEscapedAttributeValue(writer, system_id);
try writer.writeAll("\"");
}
// Internal subset is not implemented
try writer.writeAll(">");
}
pub fn writeNode(node: *parser.Node, writer: anytype) anyerror!void { pub fn writeNode(node: *parser.Node, writer: anytype) anyerror!void {
switch (try parser.nodeType(node)) { switch (try parser.nodeType(node)) {
.element => { .element => {
@@ -88,7 +114,7 @@ pub fn writeNode(node: *parser.Node, writer: anytype) anyerror!void {
.document_fragment => return, .document_fragment => return,
// document will never be called, but required for completeness. // document will never be called, but required for completeness.
.document => return, .document => return,
// done globally instead, but required for completeness. // done globally instead, but required for completeness. Only the outer DOCTYPE should be written
.document_type => return, .document_type => return,
// deprecated // deprecated
.attribute => return, .attribute => return,

View File

@@ -35,10 +35,10 @@ pub const XMLSerializer = struct {
pub fn _serializeToString(_: *const XMLSerializer, root: *parser.Node, page: *Page) ![]const u8 { pub fn _serializeToString(_: *const XMLSerializer, root: *parser.Node, page: *Page) ![]const u8 {
var buf = std.ArrayList(u8).init(page.arena); var buf = std.ArrayList(u8).init(page.arena);
if (try parser.nodeType(root) == .document) { switch (try parser.nodeType(root)) {
try dump.writeHTML(@as(*parser.Document, @ptrCast(root)), buf.writer()); .document => try dump.writeHTML(@as(*parser.Document, @ptrCast(root)), buf.writer()),
} else { .document_type => try dump.writeDocType(@as(*parser.DocumentType, @ptrCast(root)), buf.writer()),
try dump.writeNode(root, buf.writer()); else => try dump.writeNode(root, buf.writer()),
} }
return buf.items; return buf.items;
} }
@@ -54,3 +54,12 @@ test "Browser.XMLSerializer" {
.{ "s.serializeToString(document.getElementById('para'))", "<p id=\"para\"> And</p>" }, .{ "s.serializeToString(document.getElementById('para'))", "<p id=\"para\"> And</p>" },
}, .{}); }, .{});
} }
test "Browser.XMLSerializer with DOCTYPE" {
var runner = try testing.jsRunner(testing.tracking_allocator, .{ .html = "<!DOCTYPE html><html><head></head><body></body></html>" });
defer runner.deinit();
try runner.testCases(&.{
.{ "new XMLSerializer().serializeToString(document.doctype)", "<!DOCTYPE html>" },
}, .{});
}
test