OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [gnu/] [xml/] [xpath/] [Expr.java] - Blame information for rev 769

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 769 jeremybenn
/* Expr.java --
2
   Copyright (C) 2004,2006 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 gnu.java.lang.CPStringBuilder;
41
 
42
import java.io.IOException;
43
import java.text.DecimalFormat;
44
import java.text.DecimalFormatSymbols;
45
import java.util.ArrayList;
46
import java.util.Collection;
47
import java.util.Collections;
48
import java.util.Comparator;
49
import java.util.HashSet;
50
import java.util.Iterator;
51
import java.util.List;
52
import java.util.Locale;
53
import java.util.Set;
54
import java.util.StringTokenizer;
55
import javax.xml.namespace.QName;
56
import javax.xml.parsers.DocumentBuilder;
57
import javax.xml.parsers.DocumentBuilderFactory;
58
import javax.xml.parsers.ParserConfigurationException;
59
import javax.xml.xpath.XPathConstants;
60
import javax.xml.xpath.XPathExpression;
61
import javax.xml.xpath.XPathExpressionException;
62
import org.w3c.dom.Document;
63
import org.w3c.dom.Node;
64
import org.w3c.dom.NodeList;
65
import org.xml.sax.InputSource;
66
import org.xml.sax.SAXException;
67
 
68
/**
69
 * An XPath expression.
70
 * This can be evaluated in the context of a node to produce a result.
71
 *
72
 * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
73
 */
74
public abstract class Expr
75
  implements XPathExpression
76
{
77
 
78
  protected static final Comparator<Node> documentOrderComparator =
79
    new DocumentOrderComparator();
80
 
81
  protected static final DecimalFormat decimalFormat =
82
    new DecimalFormat("####################################################" +
83
                      ".####################################################",
84
                      new DecimalFormatSymbols(Locale.US));
85
 
86
  static class ExprNodeSet implements NodeList
87
  {
88
 
89
    private ArrayList<Node> list;
90
 
91
    ExprNodeSet(Collection<Node> collection)
92
    {
93
      if (collection instanceof ArrayList)
94
        list = (ArrayList<Node>) collection;
95
      else
96
        list = new ArrayList<Node>(collection);
97
    }
98
 
99
    public int getLength()
100
    {
101
      return list.size();
102
    }
103
 
104
    public Node item(int index)
105
    {
106
      try
107
        {
108
          return list.get(index);
109
        }
110
      catch (ArrayIndexOutOfBoundsException e)
111
        {
112
          return null;
113
        }
114
    }
115
 
116
  }
117
 
118
  public Object evaluate(Object item, QName returnType)
119
    throws XPathExpressionException
120
  {
121
    Object ret = null;
122
    Node context = null;
123
    if (item instanceof Node)
124
      {
125
        context = (Node) item;
126
        ret = evaluate(context, 1, 1);
127
        if (XPathConstants.STRING == returnType &&
128
            !(ret instanceof String))
129
          {
130
            ret = _string(context, ret);
131
          }
132
        else if (XPathConstants.NUMBER == returnType &&
133
                 !(ret instanceof Double))
134
          {
135
            ret = new Double(_number(context, ret));
136
          }
137
        else if (XPathConstants.BOOLEAN == returnType &&
138
                 !(ret instanceof Boolean))
139
          {
140
            ret = _boolean(context, ret) ? Boolean.TRUE : Boolean.FALSE;
141
          }
142
        else if (XPathConstants.NODE == returnType)
143
          {
144
            if (ret instanceof Collection)
145
              {
146
                /* Suppression is safe, as we know context
147
                   produces Collection<Node> */
148
                @SuppressWarnings("unchecked")
149
                  Collection<Node> ns = (Collection<Node>) ret;
150
                switch (ns.size())
151
                  {
152
                  case 0:
153
                    ret = null;
154
                    break;
155
                  case 1:
156
                    ret = ns.iterator().next();
157
                    break;
158
                  default:
159
                    throw new XPathExpressionException("multiple nodes in node-set");
160
                  }
161
              }
162
            else if (ret != null)
163
              {
164
                throw new XPathExpressionException("return value is not a node-set");
165
              }
166
          }
167
        else if (XPathConstants.NODESET == returnType)
168
          {
169
            if (ret != null && !(ret instanceof Collection))
170
              {
171
                throw new XPathExpressionException("return value is not a node-set");
172
              }
173
            if (ret != null)
174
              {
175
                /* Suppression is safe, as we know context produces Collection<Node> */
176
                @SuppressWarnings("unchecked")
177
                  Collection<Node> nodes = (Collection<Node>) ret;
178
                ret = new ExprNodeSet(nodes);
179
              }
180
          }
181
      }
182
    return ret;
183
  }
184
 
185
  public String evaluate(Object item)
186
    throws XPathExpressionException
187
  {
188
    return (String) evaluate(item, XPathConstants.STRING);
189
  }
190
 
191
  public Object evaluate(InputSource source, QName returnType)
192
    throws XPathExpressionException
193
  {
194
    try
195
      {
196
        DocumentBuilderFactory factory =
197
          new gnu.xml.dom.JAXPFactory();
198
        DocumentBuilder builder = factory.newDocumentBuilder();
199
        Document doc = builder.parse(source);
200
        return evaluate(doc, returnType);
201
      }
202
    catch (ParserConfigurationException e)
203
      {
204
        throw new XPathExpressionException(e);
205
      }
206
    catch (SAXException e)
207
      {
208
        throw new XPathExpressionException(e);
209
      }
210
    catch (IOException e)
211
      {
212
        throw new XPathExpressionException(e);
213
      }
214
  }
215
 
216
  public String evaluate(InputSource source)
217
    throws XPathExpressionException
218
  {
219
    return (String) evaluate(source, XPathConstants.STRING);
220
  }
221
 
222
  public abstract Object evaluate(Node context, int pos, int len);
223
 
224
  public abstract Expr clone(Object context);
225
 
226
  public abstract boolean references(QName var);
227
 
228
  /* -- 4.1 Node Set Functions -- */
229
 
230
  /**
231
   * The id function selects elements by their unique ID.
232
   * When the argument to id is of type node-set, then the result is
233
   * the union of the result of applying id to the string-value of each of
234
   * the nodes in the argument node-set. When the argument to id is of any
235
   * other type, the argument is converted to a string as if by a call to
236
   * the string function; the string is split into a whitespace-separated
237
   * list of tokens (whitespace is any sequence of characters matching the
238
   * production S); the result is a node-set containing the elements in the
239
   * same document as the context node that have a unique ID equal to any of
240
   * the tokens in the list.
241
   */
242
  public static Collection<Node> _id(Node context, Object object)
243
  {
244
    Set<Node> ret = new HashSet<Node>();
245
    if (object instanceof Collection)
246
      {
247
        /* Suppression is safe, as the iteration will check each value is a Node */
248
        @SuppressWarnings("unchecked")
249
          Collection<Node> nodeSet = (Collection<Node>) object;
250
        for (Iterator<Node> i = nodeSet.iterator(); i.hasNext(); )
251
          {
252
            String string = stringValue(i.next());
253
            ret.addAll(_id (context, string));
254
          }
255
      }
256
    else
257
      {
258
        Document doc = (context instanceof Document) ? (Document) context :
259
          context.getOwnerDocument();
260
        String string = _string(context, object);
261
        StringTokenizer st = new StringTokenizer(string, " \t\r\n");
262
        while (st.hasMoreTokens())
263
          {
264
            Node element = doc.getElementById(st.nextToken());
265
            if (element != null)
266
              {
267
                ret.add(element);
268
              }
269
          }
270
      }
271
    return ret;
272
  }
273
 
274
  /**
275
   * The local-name function returns the local part of the expanded-name of
276
   * the node in the argument node-set that is first in document order. If
277
   * the argument node-set is empty or the first node has no expanded-name,
278
   * an empty string is returned. If the argument is omitted, it defaults to
279
   * a node-set with the context node as its only member.
280
   */
281
  public static String _local_name(Node context, Collection<Node> nodeSet)
282
  {
283
    if (nodeSet == null || nodeSet.isEmpty())
284
      return "";
285
    Node node = firstNode(nodeSet);
286
    String ret = node.getLocalName();
287
    return (ret == null) ? "" : ret;
288
  }
289
 
290
  /**
291
   * The namespace-uri function returns the namespace URI of the
292
   * expanded-name of the node in the argument node-set that is first in
293
   * document order. If the argument node-set is empty, the first node has
294
   * no expanded-name, or the namespace URI of the expanded-name is null, an
295
   * empty string is returned. If the argument is omitted, it defaults to a
296
   * node-set with the context node as its only member.
297
   */
298
  public static String _namespace_uri(Node context, Collection<Node> nodeSet)
299
  {
300
    if (nodeSet == null || nodeSet.isEmpty())
301
      return "";
302
    Node node = firstNode(nodeSet);
303
    String ret = node.getNamespaceURI();
304
    return (ret == null) ? "" : ret;
305
  }
306
 
307
  /**
308
   * The name function returns a string containing a QName representing the
309
   * expanded-name of the node in the argument node-set that is first in
310
   * document order. The QName must represent the expanded-name with respect
311
   * to the namespace declarations in effect on the node whose expanded-name
312
   * is being represented. Typically, this will be the QName that occurred
313
   * in the XML source. This need not be the case if there are namespace
314
   * declarations in effect on the node that associate multiple prefixes
315
   * with the same namespace. However, an implementation may include
316
   * information about the original prefix in its representation of nodes;
317
   * in this case, an implementation can ensure that the returned string is
318
   * always the same as the QName used in the XML source. If the argument
319
   * node-set is empty or the first node has no expanded-name, an empty
320
   * string is returned. If the argument it omitted, it defaults to a
321
   * node-set with the context node as its only member.
322
   */
323
  public static String _name(Node context, Collection<Node> nodeSet)
324
  {
325
    if (nodeSet == null || nodeSet.isEmpty())
326
      return "";
327
    Node node = firstNode(nodeSet);
328
    String ret = null;
329
    switch (node.getNodeType())
330
      {
331
      case Node.ATTRIBUTE_NODE:
332
      case Node.ELEMENT_NODE:
333
      case Node.PROCESSING_INSTRUCTION_NODE:
334
        ret = node.getNodeName();
335
      }
336
    return (ret == null) ? "" : ret;
337
  }
338
 
339
  /**
340
   * Returns the first node in the set in document order.
341
   */
342
  static Node firstNode(Collection<Node> nodeSet)
343
  {
344
    List<Node> list = new ArrayList<Node>(nodeSet);
345
    Collections.sort(list, documentOrderComparator);
346
    return list.get(0);
347
  }
348
 
349
  /* -- 4.2 String Functions -- */
350
 
351
  /**
352
   * Implementation of the XPath <code>string</code> function.
353
   */
354
  public static String _string(Node context, Object object)
355
  {
356
    if (object == null)
357
      {
358
        return stringValue(context);
359
      }
360
    if (object instanceof String)
361
      {
362
        return (String) object;
363
      }
364
    if (object instanceof Boolean)
365
      {
366
        return object.toString();
367
      }
368
    if (object instanceof Double)
369
      {
370
        double d = ((Double) object).doubleValue();
371
        if (Double.isNaN(d))
372
          {
373
            return "NaN";
374
          }
375
        else if (d == 0.0d)
376
          {
377
            return "0";
378
          }
379
        else if (Double.isInfinite(d))
380
          {
381
            if (d < 0)
382
              {
383
                return "-Infinity";
384
              }
385
            else
386
              {
387
                return "Infinity";
388
              }
389
          }
390
        else
391
          {
392
            String ret = decimalFormat.format(d);
393
            if (ret.endsWith (".0"))
394
              {
395
                ret = ret.substring(0, ret.length() - 2);
396
              }
397
            return ret;
398
          }
399
      }
400
    if (object instanceof Collection)
401
      {
402
        /* Suppression is safe, as we fail immediately if the
403
         * first element is not a Node and don't use the rest */
404
        @SuppressWarnings("unchecked")
405
          Collection<Node> nodeSet = (Collection<Node>) object;
406
        if (nodeSet.isEmpty())
407
          {
408
            return "";
409
          }
410
        Node node = firstNode(nodeSet);
411
        return stringValue(node);
412
      }
413
    throw new IllegalArgumentException(object.toString());
414
  }
415
 
416
  /* -- 4.3 Boolean Functions -- */
417
 
418
  /**
419
   * Implementation of the XPath <code>boolean</code> function.
420
   */
421
  public static boolean _boolean(Node context, Object object)
422
  {
423
    if (object instanceof Boolean)
424
      {
425
        return ((Boolean) object).booleanValue();
426
      }
427
    if (object instanceof Double)
428
      {
429
        Double value = (Double) object;
430
        if (value.isNaN())
431
          return false;
432
        return value.doubleValue() != 0.0;
433
      }
434
    if (object instanceof String)
435
      {
436
        return ((String) object).length() != 0;
437
      }
438
    if (object instanceof Collection)
439
      {
440
        return ((Collection<?>) object).size() != 0;
441
      }
442
    return false; // TODO user defined types
443
  }
444
 
445
  /* -- 4.4 Number Functions -- */
446
 
447
  /**
448
   * Implementation of the XPath <code>number</code> function.
449
   */
450
  public static double _number(Node context, Object object)
451
  {
452
    if (object == null)
453
      {
454
        object = Collections.singleton(context);
455
      }
456
    if (object instanceof Double)
457
      {
458
        return ((Double) object).doubleValue();
459
      }
460
    if (object instanceof Boolean)
461
      {
462
        return ((Boolean) object).booleanValue() ? 1.0 : 0.0;
463
      }
464
    if (object instanceof Collection)
465
      {
466
        /* Suppression is safe, as we fail immediately if one
467
         * of the elements is not a Node */
468
        @SuppressWarnings("unchecked")
469
          Collection<Node> nodeSet = (Collection<Node>) object;
470
        // Convert node-set to string
471
        object = stringValue(nodeSet);
472
      }
473
    if (object instanceof String)
474
      {
475
        String string = ((String) object).trim();
476
        try
477
          {
478
            return Double.parseDouble(string);
479
          }
480
        catch (NumberFormatException e)
481
          {
482
            return Double.NaN;
483
          }
484
      }
485
    return Double.NaN; // TODO user-defined types
486
  }
487
 
488
  /**
489
   * Computes the XPath string-value of the specified node-set.
490
   */
491
  public static String stringValue(Collection<Node> nodeSet)
492
  {
493
    CPStringBuilder buf = new CPStringBuilder();
494
    for (Iterator<Node> i = nodeSet.iterator(); i.hasNext(); )
495
      {
496
        buf.append(stringValue(i.next()));
497
      }
498
    return buf.toString();
499
  }
500
 
501
  /**
502
   * Computes the XPath string-value of the specified node.
503
   */
504
  public static String stringValue(Node node)
505
  {
506
    return stringValue(node, false);
507
  }
508
 
509
  static String stringValue(Node node, boolean elementMode)
510
  {
511
    switch (node.getNodeType())
512
      {
513
      case Node.DOCUMENT_NODE: // 5.1 Root Node
514
      case Node.DOCUMENT_FRAGMENT_NODE:
515
      case Node.ELEMENT_NODE: // 5.2 Element Nodes
516
        CPStringBuilder buf = new CPStringBuilder();
517
        for (Node ctx = node.getFirstChild(); ctx != null;
518
             ctx = ctx.getNextSibling())
519
          {
520
            buf.append(stringValue(ctx, true));
521
          }
522
        return buf.toString();
523
      case Node.TEXT_NODE: // 5.7 Text Nodes
524
      case Node.CDATA_SECTION_NODE:
525
        return node.getNodeValue();
526
      case Node.ATTRIBUTE_NODE: // 5.3 Attribute Nodes
527
      case Node.PROCESSING_INSTRUCTION_NODE: // 5.5 Processing Instruction
528
      case Node.COMMENT_NODE: // 5.6 Comment Nodes
529
        if (!elementMode)
530
          {
531
            return node.getNodeValue();
532
          }
533
      default:
534
        return "";
535
      }
536
  }
537
 
538
  static int intValue(Object val)
539
  {
540
    if (val instanceof Double)
541
      {
542
        Double d = (Double) val;
543
        return d.isNaN() ? 0 : d.intValue();
544
      }
545
    else
546
      return (int) Math.ceil(_number(null, val));
547
  }
548
 
549
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.