XML Creating and Cloning Nodes
Creating a node does not attach it to a document. append places it into a parent; cloning makes a separate object whose identifiers need deliberate treatment.
How it works
cloneNode(true) copies descendants, while a shallow clone does not copy the subtree. Copying a packet also copies its id, which would violate the exchange’s identity rule if the clone were attached unchanged. Assign a new id before insertion and update the intended fields. Moving an existing node to a new parent is different from cloning: the original object can have only one parent at a time.
Run the code
Save this complete HTML source as index.html and open it in a normal browser. Select Run example to execute it. The document embeds its XML and runs without a network connection. Browser DOM/XPath examples do not run in the XML syntax playground.
Download the complete create-clone.html source. Keep each lab in its own folder. Sources are served as text, not as public executable server scripts. Review the starting setup.
Example
<!doctype html>
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Seed exchange XML lab</title><style>body{font:18px/1.6 system-ui;margin:24px;color:#0f3464}pre{white-space:pre-wrap;overflow-wrap:anywhere}button{font:inherit}main{max-width:55rem;margin:auto}</style></head>
<body><main><h1>Seed exchange XML lab</h1><button id="run" type="button">Run example</button><pre id="result" aria-live="polite"></pre></main>
<script>
document.querySelector('#run').addEventListener('click', async () => {
const show = value => document.querySelector('#result').textContent = String(value);
const parse = text => {
if (/<!\s*(DOCTYPE|ENTITY)/i.test(text)) throw new Error('Declarations disabled');
const doc = new DOMParser().parseFromString(text, 'application/xml');
if (doc.querySelector('parsererror')) throw new Error('Malformed XML');
return doc;
};
const doc = parse("<exchange region=\"west\">\n <packet id=\"p1\" available=\"true\"><name>Marigold</name><quantity>12</quantity><category>flower</category></packet>\n <packet id=\"p2\" available=\"false\"><name>Fenugreek</name><quantity>0</quantity><category>herb</category></packet>\n <packet id=\"p3\" available=\"true\"><name>Basil</name><quantity>7</quantity><category>herb</category></packet>\n</exchange>");
try {
const original = doc.querySelector('packet[id="p1"]');
const copy = original.cloneNode(true);
copy.setAttribute('id', 'p4');
copy.querySelector('name').textContent = 'Sunflower';
doc.documentElement.append(copy);
show(doc.querySelectorAll('packet').length + ' / ' + original.querySelector('name').textContent + ' / ' + copy.querySelector('name').textContent);
} catch (error) { show('Error: ' + error.message); }
});
</script></body></html>
Expected result
4 / Marigold / Sunflower
The original remains Marigold and the separate clone becomes Sunflower. Four packets now exist in the in-memory document. If the vocabulary uses namespaces, create new elements with createElementNS so their expanded names remain correct.
Check the exact contract in the XML specification, XPath 1.0, the XSD 1.0 primer, lxml validation documentation and Saxon’s processor documentation.