Using Saxon HE 12.7, where I have problems getting accurate location information of an XPath syntax error. Here is an SCCS that illustrates the problem:
import java.io.*;
import net.sf.saxon.*;
import net.sf.saxon.s9api.*;
public class SaxonXPathTest {
public static final void main(
String[] args
) throws Exception {
// Following expression should generate an error
String expression = "/dmAddress/\ndmIdent/\ndmCode/\n@modelIdentCode[";
Processor proc = new net.sf.saxon.s9api.Processor(new Configuration());
XPathCompiler compiler = proc.newXPathCompiler();
printExpression(expression);
try {
compiler.compilePattern(expression);
} catch (Exception e) {
System.out.println(formatSaxonExceptionMessage(e));
}
}
static void printExpression(
String text
) throws Exception
{
BufferedReader in = new BufferedReader(new StringReader(text));
String line = null;
int n = 1;
while ((line = in.readLine()) != null) {
System.out.print(n+":\t");
System.out.println(line);
++n;
}
}
static String formatSaxonExceptionMessage(
Throwable e
) {
net.sf.saxon.trans.XPathException xpe =
getSaxonXPathException(e);
if (xpe == null) {
return e.getLocalizedMessage();
}
String message = xpe.getLocalizedMessage();
Location loc = xpe.getLocator();
if (loc == null) {
return message;
}
int line = loc.getLineNumber();
int col = loc.getColumnNumber();
if ((line < 0) && (col < 0)) {
return message;
}
// XXX: Line can be negative even if column is not!!
return "Error at "+line+':'+col+": "+message;
}
static net.sf.saxon.trans.XPathException getSaxonXPathException(
Throwable e
) {
if (e == null) return null;
if (e instanceof net.sf.saxon.trans.XPathException) {
return (net.sf.saxon.trans.XPathException)e;
}
return getSaxonXPathException(e.getCause());
}
}
When the program is executed, I get the following:
1: /dmAddress/
2: dmIdent/
3: dmCode/
4: @modelIdentCode[
Error at 2:17: Expected an expression, but reached the end of the input
The line number should be 4.
Am I missing something? And is crawling the Exception cause stack the only way to get access to the Location instance associated with the exception. The main exception instance is not XPathException.
Logged as a bug here:
https://saxonica.plan.io/issues/6809
In summary, the internal line number maintained by the parser is zero-based, so it's detected on line 3, but it seems we are then subtracting 1 rather than adding 1 when we publish the line number for user consumption.
XPathCompiler.compilePattern()
should throw a SaxonApiException
, and this exception has a getLineNumber()
method, so you should be able to get the value without going to quite so much trouble.