-
Help Center home
-
Product manuals
-
Release notes
-
System requirements
Migrating print scripts from E4X to DOMParser or JSON in PaperCut NG/MF v25
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 XMLor the E4X dot-filter syntax (for exampleusers.(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:
DOMParseris 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.
- 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.
- Open your existing script and locate the
new XML(...)calls and any dot-filter orfor eachpatterns. - Replace
new XML(xmlString)withnew DOMParser().parseFromString(xmlString, 'application/xml'). - Replace dot-style property access (for example
user.currentLesson.DepartmentName) withgetElementsByTagName(...)calls and a small helper function to read text content. - 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.
- Update the middleware or upstream system that supplies the data so it sends a JSON object instead of an XML string.
- 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.
- Replace the E4X parsing call with
JSON.parse(jsonString). - Use ordinary dot or bracket access on the resulting object.
- 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
- Send a test print job (or perform the device action) that exercises the path your script handles.
- Open Logs > Application Log and confirm there are no
ReferenceError,TypeError, orSyntaxErrorentries with your script name. - 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 XMLbut 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.
DOMParseris not available in v24. You must develop on v25. -
I set
security.device-script.allow-unsafe-code=Yand 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.parsereturns a string, not an object.Check the data is not double-encoded by the middleware (a string-inside-a-string). Use
typeofto confirm what you are receiving.
Related articles
Category: How-to Articles
Subcategory: Administration
Comments