Choose your language

Choose your login

Support

How can we help?

PaperCut's AI-generated content is continually improving, but it may still contain errors. Please verify as needed.

Lightbulb icon
Lightbulb icon

Here’s your answer

Sources:

* PaperCut is constantly working to improve the accuracy and quality of our AI-generated content. However, there may still be errors or inaccuracies, we appreciate your understanding and encourage verification when needed.

Lightbulb icon

Oops!

We currently don’t have an answer for this and our teams are working on resolving the issue. If you still need help,
User reading a resource

Popular resources

Conversation bubbles

Contact us

Migrating print scripts from E4X to DOMParser or JSON in PaperCut NG/MF v25

THE PAGE APPLIES TO:

Last updated May 28, 2026

This article is for PaperCut NG and PaperCut MF administrators, system integrators, and resellers who maintain advanced print scripts.

After upgrading to PaperCut NG/MF version 25, any print script that uses new XML(...) or the ECMAScript for XML (E4X) dot-and-filter syntax will fail with errors such as ReferenceError: "XML" is not defined.

This article shows you how to rewrite those scripts using the modern DOMParser API or JSON.parse, with before-and-after examples.

Most print scripts will not be affected. Only scripts that use advanced E4X commands need to be rewritten. If your script does not contain new XML or the E4X dot-filter syntax (for example users.(name == "alice")), you can stop reading here.

The script breaks because PaperCut NG/MF v25 ships with an updated Mozilla Rhino JavaScript engine that no longer supports E4X. Common causes:

  • The script uses new XML(...) to parse an XML string into a workable object.
  • The script uses the E4X dot-filter syntax such as doc.users.user.(name == "alice").
  • The script uses for each (var x in collection) to iterate XML nodes.

Why this happens

The XML global, the new XML(...) constructor, and the E4X dot-filter syntax all come from a JavaScript extension called ECMAScript for XML (E4X). E4X was removed from Firefox in 2013 and from the Mozilla Rhino engine in 2015. PaperCut v24 and earlier shipped with an older Rhino build that still included E4X. PaperCut v25 ships with a modern Rhino build that no longer includes it.

There is no way to re-enable E4X in v25. Setting security.print-and-device.script.enabled=Y or security.device-script.allow-unsafe-code=Y in security.properties will not bring it back. Any script that depends on E4X must be rewritten.

How to fix the problem

You have two options. Choose DOMParser if your data source already returns XML and you cannot change it; choose JSON.parse if you control the middleware and can change it to emit JSON.

Important: DOMParser is only available in v25 and later. You cannot develop or test the rewritten script on a v24 server. If you need to keep a v24 server in production while you migrate, set up a v25 test environment first.

Option 1: Rewrite the script using DOMParser

Use this option when you want to keep XML as the data format.

  1. In the PaperCut Admin web interface, go to Printers > [select printer] > Scripting for a print script, or Devices > [select device] > Device Script for a device script.
  2. Open your existing script and locate the new XML(...) calls and any dot-filter or for each patterns.
  3. Replace new XML(xmlString) with new DOMParser().parseFromString(xmlString, 'application/xml').
  4. Replace dot-style property access (for example user.currentLesson.DepartmentName) with getElementsByTagName(...) calls and a small helper function to read text content.
  5. Click Apply and confirm the script editor shows no syntax errors.

Before (v24, E4X — no longer works on v25):

// E4X: parse an XML string by constructing a new XML object
var xmlString = '<user><currentLesson><DepartmentName>Maths</DepartmentName><ClassReference>10A</ClassReference></currentLesson></user>';
var user = new XML(xmlString);

// E4X dot-and-filter syntax
actions.job.chargeToSharedAccount(
   user.currentLesson.DepartmentName + '\\' + user.currentLesson.ClassReference
);

After (v25, DOMParser):

// Use JavaScript's DOMParser to interpret the XML string as an XMLDocument
var xmlString = '<user><currentLesson><DepartmentName>Maths</DepartmentName><ClassReference>10A</ClassReference></currentLesson></user>';
var domParser = new DOMParser();
var user = domParser.parseFromString(xmlString, 'application/xml');

// Helper to read text content of a child element
function getChildText(element, tagName) {
  if (!element) return '';
  var nodes = element.getElementsByTagName(tagName);
  if (nodes && nodes.length > 0 && nodes[0].textContent) {
    return nodes[0].textContent;
  }
  return '';
}

var currentLessonCollection = user.getElementsByTagName("currentLesson");
if (currentLessonCollection.length === 1) {
   var currentLesson = currentLessonCollection[0];
   actions.job.chargeToSharedAccount(
      getChildText(currentLesson, "DepartmentName") + '\\' + getChildText(currentLesson, "ClassReference")
   );
}

Replacing common E4X patterns

| E4X (old, v24 and earlier) | Modern equivalent (v25 and later) | |—|—| | var doc = new XML(str); | var doc = new DOMParser().parseFromString(str, 'application/xml'); | | doc.user.name | getChildText(doc.getElementsByTagName('user')[0], 'name') | | doc.users.user (a list) | doc.getElementsByTagName('user') (returns an HTMLCollection) | | doc.users.user.(name == "alice") | Array.from(doc.getElementsByTagName('user')).find(u => getChildText(u, 'name') === 'alice') | | for each (var u in doc.users.user) { ... } | for (var i = 0; i < users.length; i++) { var u = users[i]; ... } |

Full reference example

The example below covers traversal, iteration, and replacement of E4X’s filter syntax with Array.from(...).find(...). The helper function getChildText is the same as above.

// Use JavaScript's DOMParser to interpret the XML string as an XMLDocument
const xmlString = '<xml>...</xml>';
const domParser = new DOMParser();
const user = domParser.parseFromString(xmlString, 'application/xml');

// EXAMPLE 1
// How to traverse the XMLDocument.
{
   // Retrieve nodes from the XMLDocument using getElementsByTagName()
   // Returns an HTMLCollection, which is similar to an array of nodes.
   var currentLessonCollection = user.getElementsByTagName("currentLesson");

   if (currentLessonCollection.length == 1) {
      // Retrieve first node from collection
      var currentLesson = currentLessonCollection[0];

      try {
         // Use getChildText to pull text from currentLesson's child nodes
         actions.job.chargeToSharedAccount(
            getChildText(currentLesson, "DepartmentName") + '\\' + getChildText(currentLesson, "ClassReference")
         );
         return;
      }
      catch (err) {
         // Use either textContent or innerHTML to print the contents of the element
         actions.log.error("Failed to charge to current lesson " + currentLesson.textContent);
         return;
      }
   }
}

// EXAMPLE 2
// You can iterate through the collection like an array
{
   var lessonsCollection = user.getElementsByTagName("lessons");

   var STAGES = [];
   for (let i = 0; i < lessonsCollection.length; i++) {
      var lesson = lessonsCollection[i];
      STAGES.push(getChildText(lesson, "StageName"));
   }
}

// EXAMPLE 3
// The E4X filter syntax doesn't exist in JS anymore.
// Use Array.prototype.find() instead
{
   var lessonsCollection = user.getElementsByTagName("lessons");

   var selectStage = ...; // Defined by user input
   var chargeAccount = Array.from(lessonsCollection).find(lesson => getChildText(lesson, "StageName") == selectStage);

   actions.job.chargeToSharedAccount(
      getChildText(chargeAccount, "DepartmentName") + '\\' + getChildText(chargeAccount, "ClassReference")
   );
}

Option 2: Switch from XML to JSON

Use this option when you control the data source and can change it to emit JSON. JSON parsing in v25 is shorter and easier to maintain than XML parsing.

  1. Update the middleware or upstream system that supplies the data so it sends a JSON object instead of an XML string.
  2. In the PaperCut Admin web interface, go to Printers > [select printer] > Scripting for a print script, or Devices > [select device] > Device Script for a device script.
  3. Replace the E4X parsing call with JSON.parse(jsonString).
  4. Use ordinary dot or bracket access on the resulting object.
  5. Click Apply and confirm the script editor shows no syntax errors.

If your middleware can emit JSON like this:

{
  "currentLesson": {
    "DepartmentName": "Maths",
    "ClassReference": "10A"
  }
}

Then your print script becomes:

var jsonString = '{"currentLesson":{"DepartmentName":"Maths","ClassReference":"10A"}}';
var user = JSON.parse(jsonString);

actions.job.chargeToSharedAccount(
   user.currentLesson.DepartmentName + '\\' + user.currentLesson.ClassReference
);

JSON.parse is supported natively in the v25 Rhino engine for both print scripts and device scripts. No additional configuration is needed.

Confirm the script is working

  1. Send a test print job (or perform the device action) that exercises the path your script handles.
  2. Open Logs > Application Log and confirm there are no ReferenceError, TypeError, or SyntaxError entries with your script name.
  3. Confirm the job behaves as expected, for example the correct shared account is charged or the correct user prompt is shown.

Common pitfalls

  • My script does not use new XML but it still fails after the v25 upgrade.

    E4X is not the only thing changed in v25. Check the Important points to know about PaperCut NG/MF version 25 KB for other breaking changes, and check the script editor’s error message for the actual cause.

  • I tried to develop the new script on v24.

    DOMParser is not available in v24. You must develop on v25.

  • I set security.device-script.allow-unsafe-code=Y and it still fails.

    No security flag can re-enable E4X. E4X is removed from the engine itself.

  • My data is a JSON string but JSON.parse returns a string, not an object.

    Check the data is not double-encoded by the middleware (a string-inside-a-string). Use typeof to confirm what you are receiving.


Category: How-to Articles

Subcategory: Administration


Comments