diff --git a/src/html/dom.d b/src/html/dom.d
index dcae8c7..1d48c0d 100644
--- a/src/html/dom.d
+++ b/src/html/dom.d
@@ -471,7 +471,12 @@ struct Node {
}
}
- if (!isSelfClosing) {
+ // prefer isSelfClosing over isVoidElement to preserve xhtmlish
+ if (isSelfClosing) {
+ app.put(" />");
+ } else if (isVoidElement) {
+ app.put(">");
+ } else {
app.put('>');
switch (tagHashOf(tag_))
{
@@ -485,8 +490,6 @@ struct Node {
app.put("");
app.put(tag_);
app.put('>');
- } else {
- app.put(" />");
}
break;
case Text:
@@ -531,10 +534,10 @@ struct Node {
app.put("\"");
}
}
- if (!isSelfClosing) {
- app.put("/>");
- } else {
+ if (isSelfClosing || isVoidElement) {
app.put(">");
+ } else {
+ app.put("/>");
}
break;
case Text:
@@ -637,6 +640,29 @@ struct Node {
return (flags_ & Flags.SelfClosing) != 0;
}
+ @property isVoidElement() const {
+ if (!isElementNode)
+ return false;
+ switch (tagHashOf(tag_)) {
+ case tagHashOf("area"):
+ case tagHashOf("base"):
+ case tagHashOf("basefont"):
+ case tagHashOf("br"):
+ case tagHashOf("col"):
+ case tagHashOf("hr"):
+ case tagHashOf("img"):
+ case tagHashOf("input"):
+ case tagHashOf("isindex"):
+ case tagHashOf("link"):
+ case tagHashOf("meta"):
+ case tagHashOf("param"):
+ case tagHashOf("wbr"):
+ return true;
+ default:
+ return false;
+ }
+ }
+
@property isElementNode() const {
return type == NodeTypes.Element;
}
@@ -707,6 +733,38 @@ unittest
assert(doc.root.outerHTML == ``, doc.root.outerHTML);
}
+unittest
+{
+ // void elements should not be self-closed
+ auto doc = createDocument(`
`);
+ assert(doc.root.outerHTML == `
`, doc.root.outerHTML);
+ // svg and mathml elements can be self-closed though
+ doc = createDocument(``);
+ assert(doc.root.outerHTML == ``, doc.root.outerHTML);
+ // still preserve self-closed void tags for the sake of everyone's own preference
+ doc = createDocument(` `);
+ assert(doc.root.outerHTML == ` `, doc.root.outerHTML);
+}
+
+// toString prints elements with content as
+unittest
+{
+ // self-closed element w/o content
+ auto doc = createDocument(``);
+ assert(doc.root.firstChild.toString == `