3

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.

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for confirming the problem. I saw the getLineNumber() method, but also want the column number as I am working with a standalone XPath evaluation, so many expressions may only be 1 line, so having the column number is useful for pinpointing the location of a syntax error.
Yes, it seems reasonable to expose getColumnNumber() as well. In XSLT, XPath expressions are usually contained in XML attributes, and we have no idea where the XML attribute is relative to the containing element start tag, so in that situation the column number is fairly meaningless. But I appreciate that doesn't apply to freestanding XPath. Also, column numbers are often a bit out, because of lookahead.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.