New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Inconsistent Behaviour of node.removeChild()
#135
Comments
Thank you for providing all that information and even tests. Let me think out loud here:
Whatever we do, changing this is a breaking change, since current code might rely on removing a "child" this way. |
Hey! Thanks for the quick response to the issue, greatly appreciated! Yeah, I'm not sure what approach I'm looking for here, haha. We've got a work around in our code for this right now, but this bug certainly is a tricky one. For what it's worth, my vote is for strict adherence to the spec (as I understand it... I could be wrong):
Though you're right. That'll be a doozy of a breaking change for many people I think. Anyway, enough of my opinions on the matter. I'm sure you'll figure out what the best approach here is. 😁 To answer your question, calling const { DOMParser } = require('xmldom');
const { expect } = require('chai');
const ISSUE_CHECK = `
<xml>
<a>
<x/>
</a>
<b>
<y/>
</b>
</xml>
`.trim();
const ISSUE_CHECK_WITHOUT_Y = `
<xml>
<a>
<x/>
</a>
<b>
</b>
</xml>
`.trim();
const ISSUE_CHECK_MINIFIED = `<xml><a><x/></a><b><y/></b></xml>`;
const ISSUE_CHECK_WITHOUT_Y_MINIFIED = `<xml><a><x/></a><b/></xml>`;
describe('remove child test', () => {
it('Remove child from non-parent node pretty printed', async () => {
const dom = new DOMParser().parseFromString(ISSUE_CHECK);
const ys = dom.getElementsByTagName('y');
const as = dom.getElementsByTagName('a');
expect(dom.toString()).to.equal(ISSUE_CHECK);
const removedY = as[0].removeChild(ys[0]);
expect(removedY.toString()).to.equal('<y/>');
expect(dom.toString()).not.to.equal('');
expect(dom.toString()).to.equal(ISSUE_CHECK_WITHOUT_Y);
});
it('Remove child from non-parent node minified', async () => {
const dom = new DOMParser().parseFromString(ISSUE_CHECK_MINIFIED);
const ys = dom.getElementsByTagName('y');
const as = dom.getElementsByTagName('a');
expect(dom.toString()).to.equal(ISSUE_CHECK_MINIFIED);
const removedY = as[0].removeChild(ys[0]);
expect(removedY.toString()).to.equal('<y/>');
expect(dom.toString()).not.to.equal('');
expect(dom.toString()).to.equal(ISSUE_CHECK_WITHOUT_Y_MINIFIED);
});
}); So the first test passes for me. The document is "pretty printed" and I try to remove a child ( The second test fails for me, but not in the way I'd expect. I'm doing the same operation, but this time the document is "minified". What happens here is that the node
Thanks again for looking in to this. I hope all of this has been helpful 😄 |
This is super helpful in deed. At least it documents that this method is basically not reliable for minified XML and behaves not as specified for pretty printed XML. |
Short summary of the behavior: When removeChild is called with a parent other than My take on this issue:
|
For later reference, I found this specification (of the current, so called "Living Standard") related to node removal: https://dom.spec.whatwg.org/#concept-node-remove |
Still very important, but it slipped through. Any contributions (including tests) are welcome to get this fixed earlier, from maintainer capacity it will hopefully be part of the second next release with breaking changes (not a milestone yet). |
Update: some of the things discussed here are fixed for sure in 0.7.9, 0.8.6 and 0.9.0-beta.6 |
If nothing new pops up that has a higher prio, this will be the next topic I will work on, towards reaching the 0.9.0 milestone. |
…not a child BREAKING-CHANGE: Previously it was possible (but not documented) to call `Node.removeChild` with any node in the tree, and with certain exceptions, it would work. This is no longer the case: calling `Node.removeChild` this way will now throw a NotFoundError DOMException, as it is described by the specs. https://dom.spec.whatwg.org/#concept-node-pre-remove Fixes #135
I looked into it and I think there is no sane way of supporting the current way of "randomly removing any node by calling |
…meter BREAKING-CHANGE: Previously it was possible (but not documented) to call `Node.removeChild` with any node in the tree, and with certain exceptions, it would work. This is no longer the case: calling `Node.removeChild` this way will now throw a NotFoundError DOMException, as it is described by the specs. https://dom.spec.whatwg.org/#concept-node-pre-remove Fixes #135
…er (#494) BREAKING CHANGE: Previously it was possible (but not documented) to call `Node.removeChild` with any node in the tree, and with certain exceptions, it would work. This is no longer the case: calling `Node.removeChild` with an argument that is not a direct child of the node that it is called from, will throw a NotFoundError DOMException, as it is described by the specs. https://dom.spec.whatwg.org/#concept-node-pre-remove Fixes #135
Hello,
I'm seeing some weird behaviour when calling
node.removeChild()
. If the xml source is "minified" (no pretty formatting) then it removes the first child from the node that I'm callingremoveChild()
on. If I callremoveChild()
on the dom instance itself, it replaces the dom instance with an empty string.If however, the file is pretty printed, and I call
dom.removeChild()
ornode.removeChild()
and give it a child node (any child node in the tree) I get the tree returned back with just that node removed.I'm using xmldom version 0.3.0 in nodejs version 14.12.0 and 10.16.0.
Here's a small mocha test that demonstrates what i'm talking about
Looking at the docs on MDN (https://developer.mozilla.org/en-US/docs/Web/API/Node/removeChild) I'd expect calling
removeChild
on the dom instance itself to throw aTypeError
since I don't think the dom instance is supposed to haveremoveChild
as a function? I'd also maybe expect that callingremoveChild()
on anything but the child's direct parent to throw aNotFoundError
because the node isn't a child of the node.However, I really like the behaviour that I'm seeing in the pretty printed version of the file. It's real handy to be able to call
removeChild
on the dom instance and get it to find and remove that child from the tree, wherever it is.What is the expected behaviour of this method supposed to be?
Thanks!
Mike
The text was updated successfully, but these errors were encountered: