Source for gnu.xml.transform.Bindings

   1: /* Bindings.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.transform;
  39: 
  40: import java.util.Collection;
  41: import java.util.Collections;
  42: import java.util.HashMap;
  43: import java.util.HashSet;
  44: import java.util.Iterator;
  45: import java.util.LinkedList;
  46: import java.util.Map;
  47: import javax.xml.namespace.QName;
  48: import javax.xml.xpath.XPathVariableResolver;
  49: import org.w3c.dom.Node;
  50: 
  51: /**
  52:  * The set of variable bindings in effect for a stylesheet.
  53:  *
  54:  * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
  55:  */
  56: public class Bindings
  57:   implements XPathVariableResolver, Cloneable
  58: {
  59: 
  60:   static final int VARIABLE = 0;
  61:   static final int PARAM = 1;
  62:   static final int WITH_PARAM = 2;
  63: 
  64:   final Stylesheet stylesheet;
  65: 
  66:   /**
  67:    * Global variables.
  68:    */
  69:   final LinkedList variables;
  70: 
  71:   /**
  72:    * Parameter value stack.
  73:    */
  74:   final LinkedList parameters;
  75: 
  76:   /**
  77:    * Argument (with-param) value stack.
  78:    */
  79:   final LinkedList withParameters;
  80: 
  81:   /**
  82:    * Only search globals.
  83:    */
  84:   boolean global;
  85: 
  86:   Bindings(Stylesheet stylesheet)
  87:   {
  88:     this.stylesheet = stylesheet;
  89:     variables = new LinkedList();
  90:     parameters = new LinkedList();
  91:     withParameters = new LinkedList();
  92:     for (int i = 0; i < 3; i++)
  93:       {
  94:         push(i);
  95:       }
  96:   }
  97: 
  98:   public Object clone()
  99:   {
 100:     try
 101:       {
 102:         return (Bindings) super.clone();
 103:       }
 104:     catch (CloneNotSupportedException e)
 105:       {
 106:         throw new Error(e.getMessage());
 107:       }
 108:   }
 109: 
 110:   void push(int type)
 111:   {
 112:     switch (type)
 113:       {
 114:       case VARIABLE:
 115:         variables.addFirst(new HashMap());
 116:         break;
 117:       case PARAM:
 118:         parameters.addFirst(new HashMap());
 119:         break;
 120:       case WITH_PARAM:
 121:         withParameters.addFirst(new HashMap());
 122:         break;
 123:       }
 124:   }
 125: 
 126:   void pop(int type)
 127:   {
 128:     switch (type)
 129:       {
 130:       case VARIABLE:
 131:         variables.removeFirst();
 132:         break;
 133:       case PARAM:
 134:         parameters.removeFirst();
 135:         break;
 136:       case WITH_PARAM:
 137:         withParameters.removeFirst();
 138:         break;
 139:       }
 140:   }
 141: 
 142:   public boolean containsKey(QName name, int type)
 143:   {
 144:     if (global)
 145:       {
 146:         Map ctx1 = (Map) variables.getLast();
 147:         Map ctx2 = (Map) parameters.getLast();
 148:         return (ctx1.containsKey(name) || ctx2.containsKey(name));
 149:       }
 150:     Iterator i = null;
 151:     switch (type)
 152:       {
 153:       case VARIABLE:
 154:         i = variables.iterator();
 155:         break;
 156:       case PARAM:
 157:         i = parameters.iterator();
 158:         break;
 159:       case WITH_PARAM:
 160:         Map ctx = (Map) withParameters.getFirst();
 161:         return ctx.containsKey(name);
 162:       }
 163:     if (i != null)
 164:       {
 165:         while (i.hasNext())
 166:           {
 167:             Map ctx = (Map) i.next();
 168:             if (ctx.containsKey(name))
 169:               {
 170:                 return true;
 171:               }
 172:           }
 173:       }
 174:     return false;
 175:   }
 176: 
 177:   public Object get(QName name, Node context, int pos, int len)
 178:   {
 179:     if (global)
 180:       {
 181:         Map ctx = (Map) variables.getLast();
 182:         Object ret = ctx.get(name);
 183:         if (ret == null)
 184:           {
 185:             ctx = (Map) parameters.getLast();
 186:             ret = ctx.get(name);
 187:           }
 188:         return ret;
 189:       }
 190:     //System.err.println("bindings.get: "+name);
 191:     //System.err.println("\t"+toString());
 192:     Object ret = null;
 193:     //if (parameters.size() > 1 && containsKey(name, PARAM))
 194:       // check that template defines parameter
 195:       {
 196:         Map cwp = (Map) withParameters.getFirst();
 197:         ret = cwp.get(name);
 198:         //System.err.println("\twith-param: ret="+ret);
 199:       }
 200:     if (ret == null)
 201:       {
 202:         for (Iterator i = variables.iterator(); i.hasNext() && ret == null; )
 203:           {
 204:             Map vctx = (Map) i.next();
 205:             ret = vctx.get(name);
 206:           }
 207:         //System.err.println("\tvariable: ret="+ret);
 208:       }
 209:     if (ret == null)
 210:       {
 211:         for (Iterator i = parameters.iterator(); i.hasNext() && ret == null; )
 212:           {
 213:             Map pctx = (Map) i.next();
 214:             ret = pctx.get(name);
 215:           }
 216:         //System.err.println("\tparam: ret="+ret);
 217:       }
 218:     /*if (ret instanceof Expr && context != null)
 219:       {
 220:         Expr expr = (Expr) ret;
 221:         ret = expr.evaluate(context, 1, 1);
 222:       }*/
 223:     if (ret instanceof Node)
 224:       {
 225:         ret = Collections.singleton(ret);
 226:       }
 227:     if (ret == null)
 228:       {
 229:         ret = "";
 230:       }
 231:     //System.err.println("\tret="+ret);
 232:     return ret;
 233:   }
 234: 
 235:   void set(QName name, Object value, int type)
 236:   {
 237:     switch (type)
 238:       {
 239:       case VARIABLE:
 240:         Map vctx = (Map) variables.getFirst();
 241:         vctx.put(name, value);
 242:         break;
 243:       case PARAM:
 244:         Map pctx = (Map) parameters.getFirst();
 245:         pctx.put(name, value);
 246:         break;
 247:       case WITH_PARAM:
 248:         Map wctx = (Map) withParameters.getFirst();
 249:         wctx.put(name, value);
 250:         break;
 251:       }
 252:     //System.err.println("Set "+name+"="+value);
 253:   }
 254: 
 255:   public Object resolveVariable(QName qName)
 256:   {
 257:     return get(qName, null, 1, 1);
 258:   }
 259:   
 260:   public String toString()
 261:   {
 262:     StringBuffer buf = new StringBuffer();
 263:     boolean next = false;
 264:     Collection seen = new HashSet();
 265:     Map wctx = (Map) withParameters.getFirst();
 266:     buf.append('(');
 267:     for (Iterator i = wctx.entrySet().iterator(); i.hasNext(); )
 268:       {
 269:         if (next)
 270:           {
 271:             buf.append(',');
 272:           }
 273:         else
 274:           {
 275:             next = true;
 276:           }
 277:         Map.Entry entry = (Map.Entry) i.next();
 278:         Object key = entry.getKey();
 279:         if (!seen.contains(key))
 280:           {
 281:             buf.append(key);
 282:             buf.append('=');
 283:             buf.append(entry.getValue());
 284:             seen.add(key);
 285:           }
 286:       }
 287:     buf.append(')');
 288:     next = false;
 289:     seen.clear();
 290:     buf.append('{');
 291:     for (Iterator i = variables.iterator(); i.hasNext(); )
 292:       {
 293:         Map ctx = (Map) i.next();
 294:         for (Iterator j = ctx.entrySet().iterator(); j.hasNext(); )
 295:           {
 296:             if (next)
 297:               {
 298:                 buf.append(',');
 299:               }
 300:             else
 301:               {
 302:                 next = true;
 303:               }
 304:             Map.Entry entry = (Map.Entry) j.next();
 305:             Object key = entry.getKey();
 306:             if (!seen.contains(key))
 307:               {
 308:                 buf.append(key);
 309:                 buf.append('=');
 310:                 buf.append(entry.getValue());
 311:                 seen.add(key);
 312:               }
 313:           } 
 314:       }
 315:     buf.append('}');
 316:     next = false;
 317:     seen.clear();
 318:     buf.append('[');
 319:     for (Iterator i = parameters.iterator(); i.hasNext(); )
 320:       {
 321:         Map ctx = (Map) i.next();
 322:         for (Iterator j = ctx.entrySet().iterator(); j.hasNext(); )
 323:           {
 324:             if (next)
 325:               {
 326:                 buf.append(',');
 327:               }
 328:             else
 329:               {
 330:                 next = true;
 331:               }
 332:             Map.Entry entry = (Map.Entry) j.next();
 333:             Object key = entry.getKey();
 334:             if (!seen.contains(key))
 335:               {
 336:                 buf.append(key);
 337:                 buf.append('=');
 338:                 buf.append(entry.getValue());
 339:                 seen.add(key);
 340:               }
 341:           } 
 342:       }
 343:     buf.append(']');
 344:     return buf.toString();
 345:   }
 346: 
 347: }