diff --git a/src/builder/XMLBuilderImpl.ts b/src/builder/XMLBuilderImpl.ts index a135677..62ea924 100644 --- a/src/builder/XMLBuilderImpl.ts +++ b/src/builder/XMLBuilderImpl.ts @@ -377,6 +377,17 @@ export class XMLBuilderImpl implements XMLBuilder { const importedNode = node.node + const updateImportedNodeNs = (clone: Element) => { + // update namespace of imported node only when not specified + if (!clone._namespace) { + const [prefix] = namespace_extractQName( + clone.prefix ? clone.prefix + ':' + clone.localName : clone.localName + ); + const namespace = hostNode.lookupNamespaceURI(prefix) + new XMLBuilderImpl(clone)._updateNamespace(namespace) + } + }; + if (Guard.isDocumentNode(importedNode)) { // import document node const elementNode = importedNode.documentElement @@ -385,18 +396,14 @@ export class XMLBuilderImpl implements XMLBuilder { } const clone = hostDoc.importNode(elementNode, true) as Element hostNode.appendChild(clone) - const [prefix] = namespace_extractQName(clone.prefix ? clone.prefix + ':' + clone.localName : clone.localName) - const namespace = hostNode.lookupNamespaceURI(prefix) - new XMLBuilderImpl(clone)._updateNamespace(namespace) + updateImportedNodeNs(clone) } else if (Guard.isDocumentFragmentNode(importedNode)) { // import child nodes for (const childNode of importedNode.childNodes) { const clone = hostDoc.importNode(childNode, true) hostNode.appendChild(clone) if (Guard.isElementNode(clone)) { - const [prefix] = namespace_extractQName(clone.prefix ? clone.prefix + ':' + clone.localName : clone.localName) - const namespace = hostNode.lookupNamespaceURI(prefix) - new XMLBuilderImpl(clone)._updateNamespace(namespace) + updateImportedNodeNs(clone) } } } else { @@ -404,9 +411,7 @@ export class XMLBuilderImpl implements XMLBuilder { const clone = hostDoc.importNode(importedNode, true) hostNode.appendChild(clone) if (Guard.isElementNode(clone)) { - const [prefix] = namespace_extractQName(clone.prefix ? clone.prefix + ':' + clone.localName : clone.localName) - const namespace = hostNode.lookupNamespaceURI(prefix) - new XMLBuilderImpl(clone)._updateNamespace(namespace) + updateImportedNodeNs(clone) } } @@ -766,7 +771,7 @@ export class XMLBuilderImpl implements XMLBuilder { for (const childNode of ele.childNodes) { const newChildNode = childNode.cloneNode(true) newEle.appendChild(newChildNode) - if (Guard.isElementNode(newChildNode)) { + if (Guard.isElementNode(newChildNode) && !newChildNode._namespace) { const [newChildNodePrefix] = namespace_extractQName(newChildNode.prefix ? newChildNode.prefix + ':' + newChildNode.localName : newChildNode.localName) const newChildNodeNS = newEle.lookupNamespaceURI(newChildNodePrefix) new XMLBuilderImpl(newChildNode)._updateNamespace(newChildNodeNS) diff --git a/test/issues/issue-178.test.ts b/test/issues/issue-178.test.ts new file mode 100644 index 0000000..4ae0717 --- /dev/null +++ b/test/issues/issue-178.test.ts @@ -0,0 +1,57 @@ +import $$ from '../TestHelpers'; + +describe('Replicate issue', () => { + // https://github.com/oozcitak/xmlbuilder2/issues/90 + describe(`#178 - Namespace is removed when importing fragments.`, () => { + const expectedOutput = $$.t`txt`; + describe(`with defined namespaces on each element`, () => { + test(`using .ele()`, () => { + const doc = $$.create(); + const root = doc.ele('ns1', 'Root'); + const parent = root.ele('ns2', 'Parent'); + const child = parent.ele('ns3', 'Child'); + child.ele('ns4', 'GrandChild').txt('txt'); + + expect(doc.end()).toBe(expectedOutput); + }); + test(`using .import()`, () => { + const doc = $$.create(); + const root = doc.ele('ns1', 'Root'); + const parent = $$.fragment().ele('ns2', 'Parent'); + const child = $$.fragment().ele('ns3', 'Child'); + const grandChild = $$.fragment().ele('ns4', 'GrandChild').txt('txt'); + + child.import(grandChild); + parent.import(child); + root.import(parent); + + expect(doc.end()).toBe(expectedOutput); + }); + }); + describe(`with undefined namespaces on parent element`, () => { + const expectedOutput = $$.t`txt`; + test(`using .ele()`, () => { + const doc = $$.create(); + const root = doc.ele('ns1', 'Root'); + const parent = root.ele('Parent'); + const child = parent.ele('ns3', 'Child'); + child.ele('ns4', 'GrandChild').txt('txt'); + + expect(doc.end()).toBe(expectedOutput); + }); + test(`using .import()`, () => { + const doc = $$.create(); + const root = doc.ele('ns1', 'Root'); + const parent = $$.fragment().ele('Parent'); + const child = $$.fragment().ele('ns3', 'Child'); + const grandChild = $$.fragment().ele('ns4', 'GrandChild').txt('txt'); + + child.import(grandChild); + parent.import(child); + root.import(parent); + + expect(doc.end()).toBe(expectedOutput); + }); + }); + }); +});