adding to a child node

Post Reply
abonsey
Member
Posts: 142
Joined: Fri May 24, 2013 5:10 pm

adding to a child node

Post by abonsey »

Hi All,
I have some data supplied (see below) that has data at the parent node CustomBook that I want to add to the child node CustomBooks
I'd like to add the BatchID data to each CustomBooks node before saving.
The reason I do this is that the XML is then split later in the process using Saxon and then processed with Smartstream and I'll need the BatchID in Indesign.

Whilst I can create and add at the root level I've never been able to add it successfully at the child level.


Here's my test data
<?xml version="1.0"?>
<CustomBookProject>
<BatchID>10</BatchID>
<SourceFileName>FileA.xlsx</SourceFileName>
<CreationDateTime>2016-12-13T08:15:53.2168189+00:00</CreationDateTime>
<ProjectID>TestJob</ProjectID>
<JobCode>123456</JobCode>
<CustomBooks>
<CustomBook>
<ID>10256</ID>
<Index>1</Index>
<ID>17002314</MMU_ID>
<STATUS>EU</STUD_STATUS>
<Name_First>Andrew</Name_First>
<Name_Last>Smith</Name_Last>
<ShipmentAddress>
</ShipmentAddress>
<Pages>
</Pages>
</CustomBook>
<CustomBook>
<ID>10257</ID>
<Index>2</Index>

Thanks for any help. Hopefully I can get this cracked before the weekend festivities begin :o
freddyp
Advanced member
Posts: 1008
Joined: Thu Feb 09, 2012 3:53 pm

Re: adding to a child node

Post by freddyp »

You need a variable containing the node object with the BatchID:

Code: Select all

var batchID = yourXML.evalToNode("/CustomBookProject/BatchID");
Then you need list of all the nodes to which you want to add the batchID node as a child:

Code: Select all

var bookNodes = yourXML.evalToNodes("CustomBookProject/CustomBooks/CustomBook");
for (var i=0; i<bookNodes.length; i++) {
	bookNodes.at(i).appendChild(batchID);
}
Your XML is not complete so you may have to tweak the above somewhat, but this is the principle.
abonsey
Member
Posts: 142
Joined: Fri May 24, 2013 5:10 pm

Re: adding to a child node

Post by abonsey »

Hi,
Thanks for the quick response.
The XML has multiple CustomBook nodes before closing off. Nothing else.

I used the following but nothing appears to happen within the flow. The test flow is simple... an input folder, an XML pickup before the script is run, followed by an output folder.
The Xml just sits at the input folder before the script.

Here's my script. Any thought? This is all a bit new to me.


// Is invoked each time a new job arrives in one of the input folders for the flow element.
// The newly arrived job is passed as the second parameter.
function jobArrived( s : Switch, job : Job )
{

//Get incoming XML file as a new XML document
var theXML = new Document(job.getPath());


//Extract the BatchID node from XML
var batchID = theXML.evalToNode("/CustomBookProject/BatchID");



//Select all CustomBook nodes and append to them
var bookNodes = theXML.evalToNodes("CustomBookProject/CustomBooks/CustomBook");
for (var i=0; i<bookNodes.length; i++) {
bookNodes.at(i).appendChild(batchID);
}



// save the XML document

theXML.save(job.getPath());

}
freddyp
Advanced member
Posts: 1008
Joined: Thu Feb 09, 2012 3:53 pm

Re: adding to a child node

Post by freddyp »

You are not sending the job to an output. Add:

Code: Select all

job.sendToSingle(job.getPath());
And make sure that the script is set to have only 1 output. That is in the properties of the script in Switch Scripter.
abonsey
Member
Posts: 142
Joined: Fri May 24, 2013 5:10 pm

Re: adding to a child node

Post by abonsey »

Hi There,
Thanks for that! but it doesn't add the BatchID :(
Here's the sample xml with just one CustomBook to be updated:

<?xml version="1.0" encoding="UTF-8"?>
<CustomBookProject>
<BatchID>10</BatchID>
<SourceFileName>File.xlsx</SourceFileName>
<CreationDateTime>2016-12-13T08:15:53.2168189+00:00</CreationDateTime>
<ProjectID>Test</ProjectID>
<JobCode>123456</JobCode>
<CustomBooks>
<CustomBook>
<ID>010256</ID>
<Index>1</Index>
<Name_First>Andrew</Name_First>
<Name_Last>Smith</Name_Last>
<ShipmentAddress>
<Room_No/>
<Address_1></Address_1>
<Address_2></Address_2>
<Address_3></Address_3>
<Address_4></Address_4>
<Address_5></Address_5>
<PostCode/>
</ShipmentAddress>
<Pages>
<Page name="D" index="2"/>
<Page name="D" index="3"/>
<Page name="D" index="4"/>
<Page name="D" index="5"/>
<Page name="D" index="6"/>
<Page name="D" index="7"/>
<Page name="B" index="8"/>
<Page name="A" index="10"/>
<Page name="A" index="15"/>
</Pages>
</CustomBook>
</CustomBooks>
</CustomBookProject>


And here's the script so far:function jobArrived( s : Switch, job : Job )
function jobArrived( s : Switch, job : Job )
{

//Get incoming XML file as a new XML document
var theXML = new Document(job.getPath());


//Extract the BatchID node from XML
var batchID = theXML.evalToNode("/CustomBookProject/BatchID");



//Select all CustomBook nodes and append to them
var bookNodes = theXML.evalToNodes("CustomBookProject/CustomBooks/CustomBook");
for (var i=0; i<bookNodes.length; i++) {
bookNodes.at(i).appendChild(batchID);
}

// save the XML document
theXML.save(job.getPath());
job.sendToSingle(job.getPath());
}
freddyp
Advanced member
Posts: 1008
Joined: Thu Feb 09, 2012 3:53 pm

Re: adding to a child node

Post by freddyp »

I noticed something strange that I will have to forward to engineering, but here is something that works. Instead of getting the node and adding it as a child, this code gets the value, creates a new node and adds that as a child.

Code: Select all

function jobArrived( s : Switch, job : Job )
{

	//Get incoming XML file as a new XML document
	var theXML = new Document(job.getPath());

	//Extract the BatchID node from XML
	var batchID = theXML.evalToString("/CustomBookProject/BatchID");

	//Select all CustomBook nodes and append to them
	var bookNodes = theXML.evalToNodes("/CustomBookProject/CustomBooks/CustomBook");
	var batchIDText = theXML.createText(batchID);
	var batchIDElement = theXML.createElement("BatchID");
	batchIDElement.appendChild(batchIDText);

	for (var i=0; i<bookNodes.length; i++) {
		bookNodes.at(i).appendChild(batchIDElement);
	}

	// save the XML document
	theXML.save(job.getPath());	
	job.sendToSingle(job.getPath());
}
abonsey
Member
Posts: 142
Joined: Fri May 24, 2013 5:10 pm

Re: adding to a child node

Post by abonsey »

Hi,
That works great.
I get the result: <BatchID>10</BatchID></CustomBook>
Is there anyway to wrap the </CustomBook> to the next line?
freddyp
Advanced member
Posts: 1008
Joined: Thu Feb 09, 2012 3:53 pm

Re: adding to a child node

Post by freddyp »

That is not necessary. XML files do not have to be nicely formatted to be processed correctly.

Any XML editor will satisfy your aesthetic expectations, either automatically (open the XML with a browser for example) or by clicking on a button/menu item that formats the XML stream.
abonsey
Member
Posts: 142
Joined: Fri May 24, 2013 5:10 pm

Re: adding to a child node

Post by abonsey »

Hi freddyp,
I tried running this script again this year and the script fails. The only thing that has changed is I've upgraded Switch recently.
Can you check it still works.

UPDATE: It works with a single CustomBook but not multiples
Thanks

Andrews
abonsey
Member
Posts: 142
Joined: Fri May 24, 2013 5:10 pm

Re: adding to a child node

Post by abonsey »

Anybody able to work out why it won't work with multiple nodes in the newer version of Switch?

the problem line appears to be:
bookNodes.at(i).appendChild(batchIDElement);

Only working as singles :(

TIA
Padawan
Advanced member
Posts: 358
Joined: Mon Jun 12, 2017 8:48 pm
Location: Belgium
Contact:

Re: adding to a child node

Post by Padawan »

It looks like creating a node and adding it multiple times causes the issue. Recreating the node each time solves it.

Can you try this code?

Code: Select all

function jobArrived( s : Switch, job : Job )
{

   //Get incoming XML file as a new XML document
   var theXML = new Document(job.getPath());

   //Extract the BatchID node from XML
   var batchID = theXML.evalToString("/CustomBookProject/BatchID");

   //Select all CustomBook nodes and append to them
   var bookNodes = theXML.evalToNodes("/CustomBookProject/CustomBooks/CustomBook");
   var batchIDText = theXML.createText(batchID);


   for (var i=0; i<bookNodes.length; i++) {
	   var batchIDElement = theXML.createElement("BatchID");
  	   batchIDElement.appendChild(batchIDText);
      bookNodes.at(i).appendChild(batchIDElement);
   }

   // save the XML document
   theXML.save(job.getPath());   
   job.sendToSingle(job.getPath());
}
abonsey
Member
Posts: 142
Joined: Fri May 24, 2013 5:10 pm

Re: adding to a child node

Post by abonsey »

Thanks.
That worked. Strange it didn't work by adding it multiple time.
Post Reply