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