Source for gnu.xml.xpath.Steps

   1: /* Steps.java -- 
   2:    Copyright (C) 2004 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: package gnu.xml.xpath;
  39: 
  40: import java.util.Collection;
  41: import java.util.Collections;
  42: import java.util.Iterator;
  43: import java.util.LinkedHashSet;
  44: import java.util.LinkedList;
  45: import java.util.Set;
  46: import javax.xml.namespace.QName;
  47: import org.w3c.dom.Attr;
  48: import org.w3c.dom.Node;
  49: 
  50: /**
  51:  * A list of transitions between components in a location path.
  52:  *
  53:  * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
  54:  */
  55: public final class Steps
  56:   extends Path
  57: {
  58: 
  59:   final LinkedList path;
  60: 
  61:   public Steps()
  62:   {
  63:     this(new LinkedList());
  64:   }
  65: 
  66:   Steps(LinkedList path)
  67:   {
  68:     this.path = path;
  69:   }
  70: 
  71:   public boolean matches(Node context)
  72:   {
  73:     // Right to left
  74:     return matches(context, path.size() - 1);
  75:   }
  76: 
  77:   boolean matches(Node context, int pos)
  78:   {
  79:     Pattern right = (Pattern) path.get(pos);
  80:     if (!right.matches(context))
  81:       {
  82:         return false;
  83:       }
  84:     if (pos > 0)
  85:       {
  86:         Pattern left = (Pattern) path.get(pos - 1);
  87:         Iterator j = possibleContexts(right, context).iterator();
  88:         while (j.hasNext())
  89:           {
  90:             Node candidate = (Node) j.next();
  91:             if (left.matches(candidate) &&
  92:                 matches(candidate, pos - 1))
  93:               {
  94:                 return true;
  95:               }
  96:             // keep going, there may be another candidate
  97:           }
  98:         return false;
  99:       }
 100:     return true;
 101:   }
 102: 
 103:   /**
 104:    * Essentially the reverse of Selector.addCandidates.
 105:    * The idea is to determine possible context nodes for a match.
 106:    */
 107:   Collection possibleContexts(Pattern pattern, Node context)
 108:   {
 109:     if (pattern instanceof Selector)
 110:       {
 111:         Selector s = (Selector) pattern;
 112:         Collection candidates = new LinkedHashSet();
 113:         switch (s.axis)
 114:           {
 115:           case Selector.PARENT:
 116:             s.addChildNodes(context, candidates, false);
 117:             break;
 118:           case Selector.ANCESTOR:
 119:             s.addChildNodes(context, candidates, true);
 120:             break;
 121:           case Selector.ANCESTOR_OR_SELF:
 122:             candidates.add (context);
 123:             s.addChildNodes(context, candidates, true);
 124:             break;
 125:           case Selector.CHILD:
 126:             s.addParentNode(context, candidates, false);
 127:             break;
 128:           case Selector.DESCENDANT:
 129:             s.addParentNode(context, candidates, true);
 130:             break;
 131:           case Selector.DESCENDANT_OR_SELF:
 132:             candidates.add(context);
 133:             s.addParentNode(context, candidates, true);
 134:             break;
 135:           case Selector.PRECEDING_SIBLING:
 136:             s.addFollowingNodes(context, candidates, false);
 137:             break;
 138:           case Selector.FOLLOWING_SIBLING:
 139:             s.addPrecedingNodes(context, candidates, false);
 140:             break;
 141:           case Selector.PRECEDING:
 142:             s.addFollowingNodes(context, candidates, true);
 143:             break;
 144:           case Selector.FOLLOWING:
 145:             s.addPrecedingNodes(context, candidates, true);
 146:             break;
 147:           case Selector.ATTRIBUTE:
 148:           case Selector.NAMESPACE:
 149:             if (context.getNodeType() == Node.ATTRIBUTE_NODE)
 150:               {
 151:                 candidates.add(((Attr) context).getOwnerElement());
 152:               }
 153:             break;
 154:           case Selector.SELF:
 155:             candidates.add(context);
 156:             break;
 157:           }
 158:         return candidates;
 159:       }
 160:     return Collections.EMPTY_SET;
 161:   }
 162: 
 163:   public Object evaluate(Node context, int pos, int len)
 164:   {
 165:     //System.err.println(toString()+" evaluate");
 166:     // Left to right
 167:     Iterator i = path.iterator();
 168:     Expr lhs = (Expr) i.next();
 169:     Object val = lhs.evaluate(context, pos, len);
 170:     //System.err.println("\tevaluate "+lhs+" = "+val);
 171:     while (val instanceof Collection && i.hasNext())
 172:       {
 173:         Path rhs = (Path) i.next();
 174:         val = rhs.evaluate(context, (Collection) val);
 175:         //System.err.println("\tevaluate "+rhs+" = "+val);
 176:       }
 177:     return val;
 178:   }
 179: 
 180:   Collection evaluate(Node context, Collection ns)
 181:   {
 182:     // Left to right
 183:     Iterator i = path.iterator();
 184:     Expr lhs = (Expr) i.next();
 185:     if (lhs instanceof Path)
 186:       {
 187:         ns = ((Path) lhs).evaluate(context, ns);
 188:       }
 189:     else
 190:       {
 191:         Set acc = new LinkedHashSet();
 192:         int pos = 1, len = ns.size();
 193:         for (Iterator j = ns.iterator(); j.hasNext(); )
 194:           {
 195:             Node node = (Node) j.next();
 196:             Object ret = lhs.evaluate(node, pos++, len);
 197:             if (ret instanceof Collection)
 198:               {
 199:                 acc.addAll((Collection) ret);
 200:               }
 201:           }
 202:         ns = acc;
 203:       }
 204:     while (i.hasNext())
 205:       {
 206:         Path rhs = (Path) i.next();
 207:         ns = rhs.evaluate(context, ns);
 208:       }
 209:     return ns;
 210:   }
 211: 
 212:   public Expr clone(Object context)
 213:   {
 214:     int len = path.size();
 215:     LinkedList path2 = new LinkedList();
 216:     for (int i = 0; i < len; i++)
 217:       {
 218:         path2.add(((Expr) path.get(i)).clone(context));
 219:       }
 220:     return new Steps(path2);
 221:   }
 222: 
 223:   public boolean references(QName var)
 224:   {
 225:     for (Iterator i = path.iterator(); i.hasNext(); )
 226:       {
 227:         if (((Expr) i.next()).references(var))
 228:           {
 229:             return true;
 230:           }
 231:       }
 232:     return false;
 233:   }
 234: 
 235:   public String toString()
 236:   {
 237:     StringBuffer buf = new StringBuffer();
 238:     Iterator i = path.iterator();
 239:     Expr expr = (Expr) i.next();
 240:     if (!(expr instanceof Root))
 241:       {
 242:         buf.append(expr);
 243:       }
 244:     while (i.hasNext())
 245:       {
 246:         expr = (Expr) i.next();
 247:         buf.append('/');
 248:         buf.append(expr);
 249:       }
 250:     return buf.toString();
 251:   }
 252: 
 253: }