Hope you can help. I am currently assessing the best way to extract ALL 'OrderLevel' tags (this would include both tags and values) from an XML file in SuiteScript 2.1.
Here's an example snippet:
<RootLevel>
<OrderLevel>
<PurchaseOrderNumber>123</PurchaseOrderNumber>
<item>fridge</item>
<PurchaseOrderDate/>
<Vendor>abc</Vendor>
</OrderLevel>
<OrderLevel>
<PurchaseOrderNumber>456</PurchaseOrderNumber>
<item>cupboard</item>
<PurchaseOrderDate/>
<Vendor>def</Vendor>
</OrderLevel>
</RootLevel>
This is a very simple example of course. I was considering using a REGEX pattern, but I would rather a method that is considered best practice.
The whole goal of this exercise is to combine all tags from multiple XML files into one single XML file. To be clear, I do not want just the values, but also the tags.
Thoughts?
EDIT: Taking advice frim @Krypton, here is the SuiteScript code I have attempted to write:
// file to copy from
var childFile = file.load({id: value.fileId});
var childXmlContents = childFile.getContents();
log.debug('childXmlContents',childXmlContents);
var childXmlData = xml.Parser.fromString({text: childXmlContents});
//file to copy to
var parentFile = file.load({id: value.parentFileId});
var parentXmlContents = parentFile.getContents();
log.debug('parentXmlContents',parentXmlContents);
var parentXmlData = xml.Parser.fromString({text: parentXmlContents});
//Capture root node from parent file: We aim to copy node from child file.
const parentRootNode = parentXmlData.getElementsByTagName('RootLevel')[0];
//Capture orderLevel node from child file
var orderXMLElement = childXmlData.getElementsByTagName({tagName: 'OrderLevel'});
//Loop through each orderLevel node of child file, COPY node, then append to root of parent file
for (var i = 0; i < orderXMLElement.length; i++) {
var x = childXmlData.getElementsByTagName('OrderLevel')[i];
var getCloneNode = x.cloneNode(true);
parentRootNode.appendChild(getCloneNode);
}
//Return parent XML as string and save file
const newFileStr = xml.Parser.toString({document: parentXmlData});
const xmlFile = createXMLFile(parentFile.name, newFileStr, 6485323);
const xmlFileId = xmlFile.save();
The latest error I am receiving: SSS_XML_DOM_EXCEPTION WRONG_DOCUMENT_ERR: A node is used in a different document than the one that created it.
Ideas on what I could be doing wrong?
You can use the N/xml
module to manipulate XML files. A simple example of this is as follows - you would need to handle the loading of the files separately, this just demonstrates the XML side of it:
require(['N'], function(N) {
for(var n in N){window[n] = N[n];};
let p = xml.Parser;
let xmlString = `<RootLevel>
<OrderLevel>
<PurchaseOrderNumber>123</PurchaseOrderNumber>
<item>fridge</item>
<PurchaseOrderDate/>
<Vendor>abc</Vendor>
</OrderLevel>
<OrderLevel>
<PurchaseOrderNumber>456</PurchaseOrderNumber>
<item>cupboard</item>
<PurchaseOrderDate/>
<Vendor>def</Vendor>
</OrderLevel>
</RootLevel>`;
let xmlString2 = `
<RootLevel>
<OrderLevel>
<PurchaseOrderNumber>4567</PurchaseOrderNumber>
<item>computer</item>
<PurchaseOrderDate/>
<Vendor>xyz</Vendor>
</OrderLevel>
<OrderLevel>
<PurchaseOrderNumber>6542</PurchaseOrderNumber>
<item>mouse</item>
<PurchaseOrderDate/>
<Vendor>pqr</Vendor>
</OrderLevel>
</RootLevel>
`
let xmlDoc = p.fromString({
text: xmlString
});
let xmlDoc2 = p.fromString({
text: xmlString2
});
let xmlDocs = [xmlDoc,xmlDoc2];
let orderNodes = [];
xmlDocs.forEach( x => {
let orderNodesDoc = xml.XPath.select({
node:x,
xpath: '//OrderLevel'
});
orderNodes.push.apply(orderNodes, orderNodesDoc);
})
console.log(orderNodes);
let newXmlDoc = p.fromString({
text: '<NewRoot></NewRoot>'
});
let newRootNode = newXmlDoc.getElementsByTagName('NewRoot')[0];
console.log('newXmlDoc',newXmlDoc);
console.log(orderNodes.length);
for (i=0;i<orderNodes.length;i++) {
let orderNode = newXmlDoc.importNode(orderNodes[i], true);
newRootNode.appendChild(orderNode);
}
console.log(newXmlDoc);
let newXmlString = p.toString({
document: newXmlDoc
});
console.log('newXmlString', newXmlString);
let oldXmlString = p.toString({
document: xmlDoc
});
console.log('oldXmlString', oldXmlString);
})
Note that this is using the require
function - you can copy and paste it into your browser's dev tools console and run it directly, but will need to modify it to use define
for your production script.
HTH!