- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎03-14-2022 05:56 AM
Hi, I am trying to generate a DOCX document with the Adobe Document Generation API and save it in ServiceNow. The API-Call is described here:
https://documentcloud.adobe.com/document-services/index.html#get-documentGeneration-status
Sending a request with a document template via the REST action step of IntegrationHub to the Adobe API works fine and I get a response as described in the API documentation above. However, the response is in the "multipart/form-data" format and has two boundaries. The second boundary contains the generated document as a binary file.
Here is an example of a response. My goal is to extract the binary file in the second boundary marked in red:
There is a "Save as attachment" option to save a REST response directly as an attachment. And this is actually what I would need, but obviously it will not work if I save the whole response as an attachment, as only the part in the second boundary is the actual attachment. If I use the "Save as attachment" option, download the file, open it with an editor, manually remove everything around the actual attachment and save the file again, I can actually open it and get the DOCX document I want.
I already tried the following things quite intensively:
- Use the "Save as attachment" to save the response, then try to read the contents of the generated document into a string, cut off the stuff I don't want and save it as a new attachment. So basically doing what works if I do it manually by hand (open the file in Notepad++, remove stuff, save it again -> Works). However, it seems to be impossible to get this working directly in the instance. The resulting file is always corrupt as during Binary -> String -> Binary some bits seem to get messed up making the file not a valid DOCX file. I know there is different kinds of encodings, but I tried a lot of different encodings. And while the file almost exactly looks like the file I need, something still seems to get changed/lost along the way. The most accurate result I got was when doing it with the Cp1252 encoding. The files look almost identical, but when I compare them I can see there are minor differences, causing the file to be corrupt and not readable in Word.
Extract of comparison result. As you can see the file is almost exactly what I need, but somehow some question marks get added to the file when I modify it):
Script example to "cut away" stuff and save as new attachment (I tried various options, scoped and non-scoped. However it seems like the generated output always differs a little bit from what I would want, thus making the file corrupt):
// Must be run in global scope var gsa = new GlideSysAttachment(); var attachmentGr = new GlideRecord('sys_attachment'); attachmentGr.get('<attachmentSysId>'); var bytesContent = new GlideSysAttachment().getBytes(attachmentGr); // Attachment to string with Cp1252 encoding var dataAsString = Packages.java.lang.String(bytesContent, "Cp1252"); // Cut some stuff away to only get the binary file in the second boundary dataAsString = dataAsString.split('Content-Disposition: form-data; name="multipartLabel"')[1]; dataAsString = finalStr.split('--Boundary_')[0]; var dataAsBytes = dataAsString.getBytes("Cp1252"); gsa.write(targetRecordGr, 'output.docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', dataAsBytes);​
- Instead of using "Save as attachment" I was hoping I could just get the response body and work from there. However, I think this option does not seem to yield any results. As soon as I do "getBody" on the response, the response will be saved as a String and data from the binary file will get transformed into a string, which will data to already get lost and cause the file to be corrupt after cutting away the stuff I don't want and then saving it. So I think the moment I do "getBody" it's game over anyway.
I tried for hours to get this working and I kind of gave up and already accepted that it's just not possible. But maybe someone has any other ideas I could try or some input that could help me? Preferably without the need of doing additional scripting on a MID server to extract what I need. I know there is probably a way to get it all working via MID-Server and additional Java code or using the SDK from Adobe, but I was really hoping to get this done directly in a flow without a MID server. It's a pity that there is no way to just get the document itself back from the Adobe API, as then saving the attachment would just mean ticking the "Save as attachment" option in the Flow action.
Solved! Go to Solution.
- Labels:
-
IntegrationHub
-
Multiple Versions
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎03-14-2022 08:45 AM
We have data in ServiceNow and want to generate dynamic DOCX files out of this data. We need some advanced functionality like dynamically generate tables or having dynamic sections within the document. There are a couple of providers that offer APIs where one can pass in a JSON with data and a DOCX file with some special replacement identifiers. The Adobe Document Generation API looks like a good solution for our case as marking the identifiers in the templates is pretty easy and they provide a Word-Plugin for doing so:
https://developer.adobe.com/document-services/apis/doc-generation/
So my goal is to call their API from ServiceNow and save the resulting document back into ServiceNow.
I actually made some progress by comparing HEX codes of various files I generated with different encodings and got it working now. My problem was that I cut off a couple of characters to much from the file previously. Probably it's not a very clean or elegant solution, so I am still open for suggestions. Also this needs the Global-Scope to work. But here is a code snipped in case anyone else wants to use the Adobe API for a similar case:
var ParseMultipartFile = Class.create();
ParseMultipartFile.prototype = {
initialize: function() {},
parse: function(attachmentGr, targetRecord, filename) {
// Get bytes of attachment
var bytesContent = new GlideSysAttachment().getBytes(attachmentGr);
// Transform to ISO_8859_1 string
var dataAsString = Packages.java.lang.String(bytesContent, "ISO_8859_1");
// Extract only stuff in second boundary
var finalStr = dataAsString.split('Content-Disposition: form-data; name="multipartLabel"\r\n\r\n')[1];
finalStr = finalStr.split('\r\n--Boundary_')[0];
// Transform back to bytes
var targetInBytes = finalStr.getBytes("ISO_8859_1");
// Write attachment
var gsa = new GlideSysAttachment();
return gsa.write(targetRecord, filename, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', targetInBytes);
},
type: 'ParseMultipartFile'
};
So what we are doing now is:
- Send a template and JSON to Adobe API via REST step in a Flow
- Save the resulting response as some temporary file
- Extract the actual binary file from the temporary file with the script above
- Save the actual file (the DOCX with the filled in variables)

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎03-14-2022 08:29 AM
would you mind sharing the actual business requirement ? what are we trying to achieve here ?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎03-14-2022 08:45 AM
We have data in ServiceNow and want to generate dynamic DOCX files out of this data. We need some advanced functionality like dynamically generate tables or having dynamic sections within the document. There are a couple of providers that offer APIs where one can pass in a JSON with data and a DOCX file with some special replacement identifiers. The Adobe Document Generation API looks like a good solution for our case as marking the identifiers in the templates is pretty easy and they provide a Word-Plugin for doing so:
https://developer.adobe.com/document-services/apis/doc-generation/
So my goal is to call their API from ServiceNow and save the resulting document back into ServiceNow.
I actually made some progress by comparing HEX codes of various files I generated with different encodings and got it working now. My problem was that I cut off a couple of characters to much from the file previously. Probably it's not a very clean or elegant solution, so I am still open for suggestions. Also this needs the Global-Scope to work. But here is a code snipped in case anyone else wants to use the Adobe API for a similar case:
var ParseMultipartFile = Class.create();
ParseMultipartFile.prototype = {
initialize: function() {},
parse: function(attachmentGr, targetRecord, filename) {
// Get bytes of attachment
var bytesContent = new GlideSysAttachment().getBytes(attachmentGr);
// Transform to ISO_8859_1 string
var dataAsString = Packages.java.lang.String(bytesContent, "ISO_8859_1");
// Extract only stuff in second boundary
var finalStr = dataAsString.split('Content-Disposition: form-data; name="multipartLabel"\r\n\r\n')[1];
finalStr = finalStr.split('\r\n--Boundary_')[0];
// Transform back to bytes
var targetInBytes = finalStr.getBytes("ISO_8859_1");
// Write attachment
var gsa = new GlideSysAttachment();
return gsa.write(targetRecord, filename, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', targetInBytes);
},
type: 'ParseMultipartFile'
};
So what we are doing now is:
- Send a template and JSON to Adobe API via REST step in a Flow
- Save the resulting response as some temporary file
- Extract the actual binary file from the temporary file with the script above
- Save the actual file (the DOCX with the filled in variables)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎09-18-2024 03:45 PM
Hi Phil,
I am having same kind of response but it is Soap Response as below
--uuid: test sysid
Content-ID: test id
Content-Transfer-Encoding: 8bit
Content-Type: application/xop+xml;charset=utf-8;type="application/soap+xml"
<s:Envelope> Having some information with tags like <xop:Include> <b:Filename>fileName.PNG</b:Filename </s:Envelope>
--uuid: test sysid
Content-ID: test id1
Content-Transfer-Encoding: binary
Content-Type: application/octet-stream
=�����L'���{N��b�1���Ao�G��t�9mu.Й3��3��5�����ߵ�������;Zj?�]����M:+���zL{�T{�ϩ7�E���H� - Test base64binary content
--uuid: test sysid--
FYI: File extension can be changed randomly
You mentioned to save response as a temporary file, what should be the file extension is it .png in my case or just .txt
I have tried the above approach but its not working.
Can you please help me here