Search code examples
netsuitesuitescriptsuitescript2.0

SuiteScript 2.0 xmlToPdf - add image to PDF


I have an image in File Cabinet that I want to add to my PDF. I have a script that creates a PDF and adds that image to it.

I tested the link https://system.na2.netsuite.com${imgURL} on my browser and the image loads. However I get a strange error when I try to add it to my PDF below:

var myImageFromFileCabinet = file.load({id:10202});
imgURL = myImageFromFileCabinet.url;

xmlStr = `<body><img src="https://system.na2.netsuite.com${imgURL}"></body>`;

let pdfFile = render.xmlToPdf({ xmlString: xmlStr });
context.response.writeFile({
    file: pdfFile,
    isInline: true
});

"type":"error.SuiteScriptError","name":"USER_ERROR","message":"Error Parsing XML: The reference to entity "c" must end with the ';' delimiter.

How can I add an image to a PDF?


Solution

  • TLDR: Escape the URL string for use in XML

    The root cause of your error is that you are not escaping the URL for use in XML. The & characters in the URL must be escaped as XML/HTML entities. You can do this with the N/xml.escape() function:

    const imgURL = xml.escape({xmlText: myImageFromFileCabinet.url});
    

    That said, there were several other issues I had to resolve with this code along the way:

    Outer tag must be pdf

    The initial error I got when running this code was:

    Error Parsing XML: Outer tag is body, should be pdf or pdfset

    I fixed this by wrapping the <body> in a <pdf>.

    img tag must be closed

    Next I needed to close the <img> with </img> (or /> whichever you prefer).

    Summary

    My full working onRequest looks like:

      const onRequest = (context) => {
        const myImageFromFileCabinet = file.load({id:1820});
        const imgURL = xml.escape({xmlText: myImageFromFileCabinet.url});
    
        const xmlString = `<pdf><body><img src="https://system.na2.netsuite.com${imgURL}"/></body></pdf>`;
    
        const pdfFile = render.xmlToPdf({ xmlString });
        context.response.writeFile({
          file: pdfFile,
          isInline: true
        });
      };
    

    Note that I've also made some minor changes like renaming variables and adding some const keywords, as well as of course changing the image's internal ID for my own account.