evaluateXPathExpression vs XML-rules: which is better?

This question arose to me a few months ago I was writing a script which made changes to the document using evaluateXPathExpression — applying styles, clearing overrides.

Now I decided to answer to my own question in hope it may come in handy to the future generations.
At some point I added a couple of radio buttons so the user could decide which is better for him and choose either xml-rules or evaluateXPathExpression option. After some testing I came to conclusion that the latter is much better because it allows overcoming xPath limitations (not all, of course).
Here’s a quote from the XML rules chapter of the Adobe InDesign CS6 Scripting Guide: JavaScript (pages 200-201):

Due to the one-pass nature of this implementation, the following XPath expressions are specifically excluded:

Frankly speaking, I’m not an xPath-man and don’t quite understand what it means. But my client wanted the script to work with the last() function.
When I tried to use it with xml-rules, the script wrote the following error to console: “Adobe InDesign cannot process^1XPath expression '^2', line: 43”.
But with evaluateXPathExpression it worked as expected.
Since I know almost nothing about xPath, I used the information found on these two pages — XML and XPath and XPath Syntax — because it’s given in an easy-to-understand manner for me. (I know some coding gurus here on the Adobe scripting forum will be angry at me for mentioning the http://www.w3schools.com but please have mercy on me — a mere mortal retoucher.) I created a couple of documents for testing — copied the xml-structure and imported it to InDesign — and tested them against the path expressions posted as examples on the pages. Here’s the archive with the InDesign documents (CC 2014) — their IDML versions are also included — and the scripts I used for testing.

Here are the examples that work with evaluateXPathExpression, but don’t work with xml-rules producing an error:

This one doesn’t work with xml-rules silently producing no error:

The doesn’t work with both — xml-rules (producing an error) and evaluateXPathExpression (no error):

The following doesn’t work with both silently:

Here are the simple scripts I used for testing (I just copied-pasted xPath expressions into the relative lines):

evaluateXPathExpression

var scriptName = "evaluateXPathExpression test",
doc;
Main();

function Main() {
	var xmlElement;
	
	if (app.documents.length == 0) ErrorExit("Please open a document and try again.", true);
	doc = app.activeDocument;
	
	var xmlRoot = doc.xmlElements[0];
	var xmlElements = xmlRoot.evaluateXPathExpression("/bookstore/book[last()]");

	if (xmlElements.length > 0) {
		$.writeln("==================\r");
	}
	else {
		$.writeln("No elements were found");
	}

	for (var i = 0; i < xmlElements.length; i++) {
		xmlElement = xmlElements[i];
		$.writeln((i + 1) + " - " + xmlElement.contents.substring(0, 30).replace(/\s+/g, " ") + "...");
	}
}

function ErrorExit(error, icon) {
	alert(error, scriptName, icon);
	exit();
}

XML-rules

var scriptName = "XML-rules test",
doc,
glueFile = new File(app.filePath + "/Scripts/xml rules/glue code.jsx"),
count = 0;

PreCheck();
app.doScript(glueFile, ScriptLanguage.JAVASCRIPT);
Main();

function Main() {
	$.writeln("==================\r");
	var ruleSet = [new ProcessTag];
	with (doc) {
		var elements = xmlElements;
		try {
			__processRuleSet(elements[0], ruleSet);
		}
		catch(err) {
			$.writeln(err.message + ", line: " + err.line);
		}
	}
}

function ProcessTag() {
	this.name = "ProcessTag";
	this.xpath = "/bookstore/book[last()]";
	this.apply = function(xmlElement, ruleProcessor) {
		ProcessAttributes(xmlElement);
		return true;
	}
}

function ProcessAttributes(xmlElement) {
	count++;
	$.writeln(count + " - " + xmlElement.contents.substring(0, 30).replace(/\s+/g, " ") + "...");
}

function PreCheck() {
	if (app.documents.length == 0) ErrorExit("Please open a document and try again.", true);
	doc = app.activeDocument;
	if (!app.activeDocument.saved) ErrorExit("The current document has not been saved since it was created. Please save the document and try again.", true);
	if (!glueFile.exists) ErrorExit("\"glue code.jsx\" should be located in the \"Scripts > xml rules\" folder for this script to work.", true);
}

function ErrorExit(error, icon) {
	alert(error, scriptName, icon);
	exit();
}

Now a very important note: when I tested xPath expressions using evaluateXPathExpression, it worked well with my simple test files, but when my client gave me his “real” document with a complex xml-structure, it stopped working for some reason.

A couple of years ago (or more) I found out that it was somehow associated with namespaces: no namespaces — no problem.
Now, after a more careful investigation I’ve discovered that it depends on the attributes in all the parent xml-elements starting from the element we’re looking for and up to the root. The problem occurs because of the elements whose names contain colons.
For example, we’re looking for //sec/p[last()] (the last p element in every sec element). In the screenshot below, it’s marked in green.
The elements marked in red prevent the script from working properly. My idea was to temporarily replace colons, say, with underscores — or any other valid character, in case underscores are used in attribute names — so I came up with the following script:

My idea was to temporarily replace colons, say, with underscores — or any other valid character, in case underscores are used in attribute names — so I came up with the Prepare xml-attributes script.

You can test it against the xPath test-2-with namespaces.indd which is included in the archive.

First I use the 1-st button — Prepare xml-attributes — to replace colons with underscores:

Before

Progress bar

After

Final report

Finally, after making changes to the document using evaluateXPathExpression — applying styles, clearing overrides, etc. — I restore colons with the 2-nd button so the original xml-structure remains intact.

In my opinion, using evaluateXPathExpression provides huge possibilities. Such a script can save hundreds of working hours. I'd be glad to get feedback on this topic: new problems and their solutions, new xPath examples with comments — what they should do, if they work, or not ... why they don't work, etc. — in this thread at Adobe scripting forum.

I can't promise I would reply to every question because I have to do my regular work and care about my family, but I'll read it with great interest and look into it if time permits.