Skip to main content

Compiling XPaths

HC kicks off with a first implementation of DFA construction

Return to article.


Listing 1: XPathParser.java
package org.ananas.hc.compiler;

import java.util.StringTokenizer;
import org.ananas.hc.MessageStore;
import org.xml.sax.helpers.NamespaceSupport;

public class XPathParser
{
   private NamespaceSupport namespace = null;
   private MessageStore message = null;
   private Messenger messenger = null;

   public XPathParser(NamespaceSupport namespace,
                      MessageStore message,
                      Messenger messenger)
   {
      if(namespace == null)
         throw new IllegalArgumentException("NamespaceSupport is null");
      else
         this.namespace = namespace;
      if(message == null)
         throw new IllegalArgumentException("MessageStore is null");
      else
         this.message = message;
      if(messenger == null)
         this.messenger = new DefaultMessenger();
      else
         this.messenger = messenger;
   }

   public XPathParser(NamespaceSupport namespace,
                      MessageStore message)
   {
      this(namespace,message,null);
   }

   public XPathNode xpath(String xpath)
      throws CompilerException
   {
      XPathNode root = null,
                right = null;
      String[] names = new String[3];
      StringTokenizer tokenizer = new StringTokenizer(xpath,"/[]",true);
      String lookahead = tokenizer.hasMoreTokens() ?
                         tokenizer.nextToken() : null;
      while(lookahead != null)
      {
         if(lookahead.startsWith("@") && right == null)
         {
            if(namespace.processName(
                       lookahead.substring(1),names,true) == null)
               error("InvalidQName",
                     new Object[] { lookahead, xpath });
            else
               right = new XPathNode(XPathNode.ATTRIBUTE,
                                     names[0],names[1]);
         }
         else if(Character.isLetter(lookahead.charAt(0)) &&
                 right == null)
         {
            if(namespace.processName(lookahead,names,false) == null)
               error("InvalidQName",new Object[] { lookahead, xpath });
            else
               right = new XPathNode(XPathNode.ELEMENT,
                                     names[0],names[1]);
         }
         else if(lookahead.equals("/"))
         {
            if(root == null)
               root = new XPathNode(XPathNode.ROOT);
            else if(right == null)
               error("ElementOrAttributeExpected",
                     new Object[] { lookahead, xpath });
            else
               right = null;
         }
         else
            // currently a condition (e.g. simpara[ulink]) is an error
            error("ElementAttributeOrSlashExpected",
                  new Object[] { lookahead, xpath });
         lookahead = tokenizer.hasMoreTokens() ?
                     tokenizer.nextToken() : null;
         if(root == null)
            root = right;
         else if(right != null)
            root = new XPathNode(XPathNode.PARENT_OF,root,right);
      }
      return root;
   }

   public XPathNode axpath(String xpath,int priority,Object data)
      throws CompilerException
   {
      return new XPathNode(XPathNode.PARENT_OF,
                           xpath(xpath),
                           new XPathNode(XPathNode.END_MARK,
                                         priority,
                                         data));
   }

   protected final void error(String key,Object[] arguments)
      throws CompilerException
   {
      messenger.error(new CompilerException(
                             message.getMessage(key,arguments)));
   }
}

Return to article.