1:
37:
38: package ;
39:
40: import ;
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56: import ;
57: import ;
58: import ;
59: import ;
60: import ;
61: import ;
62: import ;
63: import ;
64: import ;
65:
66:
72: public abstract class Expr
73: implements XPathExpression
74: {
75:
76: protected static final Comparator documentOrderComparator =
77: new DocumentOrderComparator();
78:
79: protected static final DecimalFormat decimalFormat =
80: new DecimalFormat("####################################################" +
81: ".####################################################",
82: new DecimalFormatSymbols(Locale.US));
83:
84: static class ExprNodeSet implements NodeList
85: {
86:
87: private ArrayList list;
88:
89: ExprNodeSet(Collection collection)
90: {
91: if (collection instanceof ArrayList)
92: list = (ArrayList) collection;
93: else
94: list = new ArrayList(collection);
95: }
96:
97: public int getLength()
98: {
99: return list.size();
100: }
101:
102: public Node item(int index)
103: {
104: try
105: {
106: return (Node) list.get(index);
107: }
108: catch (ArrayIndexOutOfBoundsException e)
109: {
110: return null;
111: }
112: }
113:
114: }
115:
116: public Object evaluate(Object item, QName returnType)
117: throws XPathExpressionException
118: {
119: Object ret = null;
120: Node context = null;
121: if (item instanceof Node)
122: {
123: context = (Node) item;
124: ret = evaluate(context, 1, 1);
125: if (XPathConstants.STRING == returnType &&
126: !(ret instanceof String))
127: {
128: ret = _string(context, ret);
129: }
130: else if (XPathConstants.NUMBER == returnType &&
131: !(ret instanceof Double))
132: {
133: ret = new Double(_number(context, ret));
134: }
135: else if (XPathConstants.BOOLEAN == returnType &&
136: !(ret instanceof Boolean))
137: {
138: ret = _boolean(context, ret) ? Boolean.TRUE : Boolean.FALSE;
139: }
140: else if (XPathConstants.NODE == returnType)
141: {
142: if (ret instanceof Collection)
143: {
144: Collection ns = (Collection) ret;
145: switch (ns.size())
146: {
147: case 0:
148: ret = null;
149: break;
150: case 1:
151: ret = (Node) ns.iterator().next();
152: break;
153: default:
154: throw new XPathExpressionException("multiple nodes in node-set");
155: }
156: }
157: else if (ret != null)
158: {
159: throw new XPathExpressionException("return value is not a node-set");
160: }
161: }
162: else if (XPathConstants.NODESET == returnType)
163: {
164: if (ret != null && !(ret instanceof Collection))
165: {
166: throw new XPathExpressionException("return value is not a node-set");
167: }
168: if (ret != null)
169: ret = new ExprNodeSet((Collection) ret);
170: }
171: }
172: return ret;
173: }
174:
175: public String evaluate(Object item)
176: throws XPathExpressionException
177: {
178: return (String) evaluate(item, XPathConstants.STRING);
179: }
180:
181: public Object evaluate(InputSource source, QName returnType)
182: throws XPathExpressionException
183: {
184: try
185: {
186: DocumentBuilderFactory factory =
187: new gnu.xml.dom.JAXPFactory();
188: DocumentBuilder builder = factory.newDocumentBuilder();
189: Document doc = builder.parse(source);
190: return evaluate(doc, returnType);
191: }
192: catch (ParserConfigurationException e)
193: {
194: throw new XPathExpressionException(e);
195: }
196: catch (SAXException e)
197: {
198: throw new XPathExpressionException(e);
199: }
200: catch (IOException e)
201: {
202: throw new XPathExpressionException(e);
203: }
204: }
205:
206: public String evaluate(InputSource source)
207: throws XPathExpressionException
208: {
209: return (String) evaluate(source, XPathConstants.STRING);
210: }
211:
212: public abstract Object evaluate(Node context, int pos, int len);
213:
214: public abstract Expr clone(Object context);
215:
216: public abstract boolean references(QName var);
217:
218:
219:
220:
232: public static Collection _id(Node context, Object object)
233: {
234: Set ret = new HashSet();
235: if (object instanceof Collection)
236: {
237: Collection nodeSet = (Collection) object;
238: for (Iterator i = nodeSet.iterator(); i.hasNext(); )
239: {
240: String string = stringValue((Node) i.next());
241: ret.addAll(_id (context, string));
242: }
243: }
244: else
245: {
246: Document doc = (context instanceof Document) ? (Document) context :
247: context.getOwnerDocument();
248: String string = _string(context, object);
249: StringTokenizer st = new StringTokenizer(string, " \t\r\n");
250: while (st.hasMoreTokens())
251: {
252: Node element = doc.getElementById(st.nextToken());
253: if (element != null)
254: {
255: ret.add(element);
256: }
257: }
258: }
259: return ret;
260: }
261:
262:
269: public static String _local_name(Node context, Collection nodeSet)
270: {
271: if (nodeSet == null || nodeSet.isEmpty())
272: return "";
273: Node node = firstNode(nodeSet);
274: String ret = node.getLocalName();
275: return (ret == null) ? "" : ret;
276: }
277:
278:
286: public static String _namespace_uri(Node context, Collection nodeSet)
287: {
288: if (nodeSet == null || nodeSet.isEmpty())
289: return "";
290: Node node = firstNode(nodeSet);
291: String ret = node.getNamespaceURI();
292: return (ret == null) ? "" : ret;
293: }
294:
295:
311: public static String _name(Node context, Collection nodeSet)
312: {
313: if (nodeSet == null || nodeSet.isEmpty())
314: return "";
315: Node node = firstNode(nodeSet);
316: String ret = null;
317: switch (node.getNodeType())
318: {
319: case Node.ATTRIBUTE_NODE:
320: case Node.ELEMENT_NODE:
321: case Node.PROCESSING_INSTRUCTION_NODE:
322: ret = node.getNodeName();
323: }
324: return (ret == null) ? "" : ret;
325: }
326:
327:
330: static Node firstNode(Collection nodeSet)
331: {
332: List list = new ArrayList(nodeSet);
333: Collections.sort(list, documentOrderComparator);
334: return (Node) list.get(0);
335: }
336:
337:
338:
339:
342: public static String _string(Node context, Object object)
343: {
344: if (object == null)
345: {
346: return stringValue(context);
347: }
348: if (object instanceof String)
349: {
350: return (String) object;
351: }
352: if (object instanceof Boolean)
353: {
354: return object.toString();
355: }
356: if (object instanceof Double)
357: {
358: double d = ((Double) object).doubleValue();
359: if (Double.isNaN(d))
360: {
361: return "NaN";
362: }
363: else if (d == 0.0d)
364: {
365: return "0";
366: }
367: else if (Double.isInfinite(d))
368: {
369: if (d < 0)
370: {
371: return "-Infinity";
372: }
373: else
374: {
375: return "Infinity";
376: }
377: }
378: else
379: {
380: String ret = decimalFormat.format(d);
381: if (ret.endsWith (".0"))
382: {
383: ret = ret.substring(0, ret.length() - 2);
384: }
385: return ret;
386: }
387: }
388: if (object instanceof Collection)
389: {
390: Collection nodeSet = (Collection) object;
391: if (nodeSet.isEmpty())
392: {
393: return "";
394: }
395: Node node = firstNode(nodeSet);
396: return stringValue(node);
397: }
398: throw new IllegalArgumentException(object.toString());
399: }
400:
401:
402:
403:
406: public static boolean _boolean(Node context, Object object)
407: {
408: if (object instanceof Boolean)
409: {
410: return ((Boolean) object).booleanValue();
411: }
412: if (object instanceof Double)
413: {
414: Double value = (Double) object;
415: if (value.isNaN())
416: return false;
417: return value.doubleValue() != 0.0;
418: }
419: if (object instanceof String)
420: {
421: return ((String) object).length() != 0;
422: }
423: if (object instanceof Collection)
424: {
425: return ((Collection) object).size() != 0;
426: }
427: return false;
428: }
429:
430:
431:
432:
435: public static double _number(Node context, Object object)
436: {
437: if (object == null)
438: {
439: object = Collections.singleton(context);
440: }
441: if (object instanceof Double)
442: {
443: return ((Double) object).doubleValue();
444: }
445: if (object instanceof Boolean)
446: {
447: return ((Boolean) object).booleanValue() ? 1.0 : 0.0;
448: }
449: if (object instanceof Collection)
450: {
451:
452: object = stringValue((Collection) object);
453: }
454: if (object instanceof String)
455: {
456: String string = ((String) object).trim();
457: try
458: {
459: return Double.parseDouble(string);
460: }
461: catch (NumberFormatException e)
462: {
463: return Double.NaN;
464: }
465: }
466: return Double.NaN;
467: }
468:
469:
472: public static String stringValue(Collection nodeSet)
473: {
474: StringBuffer buf = new StringBuffer();
475: for (Iterator i = nodeSet.iterator(); i.hasNext(); )
476: {
477: buf.append(stringValue((Node) i.next()));
478: }
479: return buf.toString();
480: }
481:
482:
485: public static String stringValue(Node node)
486: {
487: return stringValue(node, false);
488: }
489:
490: static String stringValue(Node node, boolean elementMode)
491: {
492: switch (node.getNodeType())
493: {
494: case Node.DOCUMENT_NODE:
495: case Node.DOCUMENT_FRAGMENT_NODE:
496: case Node.ELEMENT_NODE:
497: StringBuffer buf = new StringBuffer();
498: for (Node ctx = node.getFirstChild(); ctx != null;
499: ctx = ctx.getNextSibling())
500: {
501: buf.append(stringValue(ctx, true));
502: }
503: return buf.toString();
504: case Node.TEXT_NODE:
505: case Node.CDATA_SECTION_NODE:
506: return node.getNodeValue();
507: case Node.ATTRIBUTE_NODE:
508: case Node.PROCESSING_INSTRUCTION_NODE:
509: case Node.COMMENT_NODE:
510: if (!elementMode)
511: {
512: return node.getNodeValue();
513: }
514: default:
515: return "";
516: }
517: }
518:
519: static int intValue(Object val)
520: {
521: if (val instanceof Double)
522: {
523: Double d = (Double) val;
524: return d.isNaN() ? 0 : d.intValue();
525: }
526: else
527: return (int) Math.ceil(_number(null, val));
528: }
529:
530: }