Skip to content

Commit

Permalink
fix: No longer serialize any namespaces with an empty URI (#244)
Browse files Browse the repository at this point in the history
  • Loading branch information
karfau committed Jun 9, 2021
1 parent 23570ce commit be3b3e6
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 26 deletions.
27 changes: 15 additions & 12 deletions lib/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -962,10 +962,17 @@ function nodeSerializeToString(isHtml,nodeFilter){
return buf.join('');
}

function needNamespaceDefine(node,isHTML, visibleNamespaces) {
var prefix = node.prefix||'';
function needNamespaceDefine(node, isHTML, visibleNamespaces) {
var prefix = node.prefix || '';
var uri = node.namespaceURI;
if (!prefix && !uri){
// According to [Namespaces in XML 1.0](https://www.w3.org/TR/REC-xml-names/#ns-using) ,
// and more specifically https://www.w3.org/TR/REC-xml-names/#nsc-NoPrefixUndecl :
// > In a namespace declaration for a prefix [...], the attribute value MUST NOT be empty.
// in a similar manner [Namespaces in XML 1.1](https://www.w3.org/TR/xml-names11/#ns-using)
// and more specifically https://www.w3.org/TR/xml-names11/#nsc-NSDeclared :
// > [...] Furthermore, the attribute value [...] must not be an empty string.
// so serializing empty namespace value like xmlns:ds="" would produce an invalid XML document.
if (!uri) {
return false;
}
if (prefix === "xml" && uri === NAMESPACE.XML || uri === NAMESPACE.XMLNS) {
Expand All @@ -976,8 +983,8 @@ function needNamespaceDefine(node,isHTML, visibleNamespaces) {
while (i--) {
var ns = visibleNamespaces[i];
// get namespace prefix
if (ns.prefix == prefix){
return ns.namespace != uri;
if (ns.prefix === prefix) {
return ns.namespace !== uri;
}
}
return true;
Expand Down Expand Up @@ -1035,13 +1042,9 @@ function serializeToString(node,buf,isHTML,nodeFilter,visibleNamespaces){
if (needNamespaceDefine(node,isHTML, visibleNamespaces)) {
var prefix = node.prefix||'';
var uri = node.namespaceURI;
if (uri) {
// Avoid empty namespace value like xmlns:ds=""
// Empty namespace URL will we produce an invalid XML document
var ns = prefix ? ' xmlns:' + prefix : " xmlns";
buf.push(ns, '="' , uri , '"');
visibleNamespaces.push({ prefix: prefix, namespace:uri });
}
var ns = prefix ? ' xmlns:' + prefix : " xmlns";
buf.push(ns, '="' , uri , '"');
visibleNamespaces.push({ prefix: prefix, namespace:uri });
}

if(child || isHTML && !/^(?:meta|link|img|br|hr|input)$/i.test(nodeName)){
Expand Down
24 changes: 24 additions & 0 deletions test/dom/serializer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,28 @@ describe('XML Serializer', () => {
'<script xmlns="http://www.w3.org/1999/xhtml"></script>'
)
})

describe('does not serialize namespaces with an empty URI', () => {
// for more details see the comments in lib/dom.js:needNamespaceDefine
it('that are used in a node', () => {
const source = '<w:p><w:r>test1</w:r><w:r>test2</w:r></w:p>'
const { documentElement } = new DOMParser().parseFromString(source)

expect(documentElement.firstChild.firstChild).toMatchObject({
nodeValue: 'test1',
})
expect(documentElement.lastChild.firstChild).toMatchObject({
nodeValue: 'test2',
})

expect(documentElement.toString()).toStrictEqual(source)
})

it('that are used in an attribute', () => {
const source = '<w:p w:attr="val"/>'
const { documentElement } = new DOMParser().parseFromString(source)

expect(documentElement.toString()).toStrictEqual(source)
})
})
})
14 changes: 0 additions & 14 deletions test/parse/node.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,20 +87,6 @@ describe('XML Node Parse', () => {
})
})

it('prefixed without empty namespace', () => {
const source = '<w:p><w:r>test1</w:r><w:r>test2</w:r></w:p>'
const { documentElement } = new DOMParser().parseFromString(source)

expect(documentElement.firstChild.firstChild).toMatchObject({
nodeValue: 'test1',
})
expect(documentElement.lastChild.firstChild).toMatchObject({
nodeValue: 'test2',
})

expect(documentElement.toString()).toStrictEqual(source)
})

it('cdata comment', () => {
const { documentElement } = new DOMParser().parseFromString(
'<xml>start <![CDATA[<encoded>]]> <!-- comment -->end</xml>'
Expand Down

0 comments on commit be3b3e6

Please sign in to comment.