Geertjan's Blog

  • February 28, 2015

Handy HyperlinkProvider

Geertjan Wielenga
Product Manager
NCX files are XML files with a specific file extension, "ncx", which are part of EPUB, and below you can see that when I hold down the Ctrl-key and move over a "src" attribute in an NCX file, a hyperlink appears, which when clicked opens the referenced file.

The hyperlink code is as follows:

@MimeRegistration(mimeType = "text/ncx+xml", service = HyperlinkProvider.class)
public class NcxHyperlinkProvider implements HyperlinkProvider {

    private static String SRC_IDENTIFIER = "src";
    private String identifier;
    private int targetStart;
    private int targetEnd;

    public boolean isHyperlinkPoint(Document doc, int offset) {
        return verifyState(doc, offset);

    public boolean verifyState(Document doc, int offset) {
        TokenHierarchy hi = TokenHierarchy.get(doc);
        TokenSequence<XMLTokenId> ts = hi.tokenSequence(XMLTokenId.language());
        Token<XMLTokenId> tok = ts.token();
        if (tok != null) {
            int tokOffset = ts.offset();
            switch (tok.id()) {
                case VALUE:
                    while (ts.movePrevious()) {
                        Token<XMLTokenId> prev = ts.token();
                        switch (prev.id()) {
                            case ARGUMENT:
                                if (SRC_IDENTIFIER.equals(prev.text().toString())) {
                                    identifier = tok.text().toString();
                                    targetStart = tokOffset;
                                    targetEnd = targetStart + tok.text().length();
                                    return true;
                            case OPERATOR:
                            case EOL:
                            case ERROR:
                            case WS:
                                return false;
                    return false;
            return false;
        return false;

    public int[] getHyperlinkSpan(Document document, int offset) {
        if (verifyState(document, offset)) {
            return new int[]{targetStart, targetEnd};
        } else {
            return null;

    public void performClickAction(Document doc, int offset) {
        identifier = identifier.replaceAll("\"", "");
        FileObject fo = Utilities.actionsGlobalContext().lookup(FileObject.class);
        String path = fo.getParent().getPath();
        File file = new File(path + "/" + identifier);
        if (file.exists() && file.isFile()) {
            try {
            } catch (DataObjectNotFoundException ex) {


All the code: https://java.net/projects/epubopentoolbox/sources/epub/show/80/fosfor/fosfor-ncx.

Join the discussion

Comments ( 1 )
  • Jirka Chmiel Sunday, March 15, 2015


    Thank you for your post. It is useful. So and what are we doing when there are more file candidates. Is there anyway how to display a context menu (or something like that) with all file candidates so that user could choose one of them and then that file open in editor? Thanks.

Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.