ZorbaXQItem.java
Go to the documentation of this file.
1 /*
2  * Copyright 2006-2012 The FLWOR Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.zorbaxquery.api.xqj;
17 
18 import java.io.*;
19 import java.math.BigDecimal;
20 import java.math.BigInteger;
21 import java.net.URI;
22 import java.util.Properties;
23 import javax.xml.datatype.DatatypeFactory;
24 import javax.xml.namespace.QName;
25 import javax.xml.parsers.DocumentBuilder;
26 import javax.xml.parsers.DocumentBuilderFactory;
27 import javax.xml.stream.XMLInputFactory;
28 import javax.xml.stream.XMLStreamReader;
29 import javax.xml.transform.Result;
30 import javax.xml.transform.Source;
31 import javax.xml.transform.Transformer;
32 import javax.xml.transform.TransformerFactory;
33 import javax.xml.transform.dom.DOMSource;
34 import javax.xml.xquery.XQException;
35 import javax.xml.xquery.XQItemType;
36 import org.w3c.dom.Document;
37 import org.w3c.dom.Element;
38 import org.w3c.dom.Node;
39 import org.xml.sax.ContentHandler;
40 import org.xml.sax.InputSource;
41 import org.xml.sax.helpers.AttributesImpl;
42 import org.zorbaxquery.api.*;
43 
44 /**
45  * This class represents an item in the XDM.
46  * This class also implements the common interface XQItemAccessor for accessing the values of an XQuery item. All the get functions raise an exception if the underlying sequence object is not positioned on an item (e.g. if the sequence is positioned before the first item or after the last item).
47  *
48  * Example -
49  *
50  * \code{.java}
51  * XQPreparedExpression expr = conn.prepareExpression("for $i ..");
52  * XQSequence result = expr.executeQuery();
53  *
54  * // create the ItemTypes for string and integer
55  * ZorbaXQItemType strType = conn.createAtomicType(ZorbaXQItemType.XQBASETYPE_STRING);
56  * ZorbaXQItemType intType = conn.createAtomicType(ZorbaXQItemType.XQBASETYPE_INTEGER);
57  *
58  * // posititioned before the first item
59  * while (result.next())
60  * {
61  * // If string or any of its subtypes, then get the string value out
62  *
63  * if (result.instanceOf(strType))
64  * String str = result.getAtomicValue();
65  * else if (result.instanceOf(intType))
66  * // if it is exactly an int
67  * int intval = result.getInt();
68  * ...
69  *
70  * // Alternatively, you can get the exact type out.
71  * ZorbaXQItemType type = result.getItemType();
72  *
73  * // Now perform the comparison..
74  * if (type.equals(intType))
75  * { ... };
76  *
77  * }
78  * \endcode
79  * See also:
80  * Table 6 - XQuery Atomic Types and Corresponding Java Object Types, XQuery API for Java (XQJ) 1.0, for mapping of XQuery atomic types to Java object types. For example, if the XQuery value returned is of type xs:unsignedByte, then calling the getObject() method will return a Java object of type java.lang.Short.
81  * Table 7 - XQuery Node Types and Corresponding Java Object Types XQuery API for Java (XQJ) 1.0, for the mapping of XQuery node types to the corresponding Java object types. For example, if the XQuery value returned is an element node, then calling the getObject() or getNode() method will return a Java object of type org.w3.dom.Element.
82  *
83 
84  */
85 class ZorbaXQItem implements javax.xml.xquery.XQItem {
86 
87  private Item item;
88  private boolean closed=false;
89  private XQItemType itemType;
90 
91  protected Item getZorbaItem() {
92  return item;
93  }
94 
95  public ZorbaXQItem(XQItemType itemType) {
96  this.itemType = itemType;
97  }
98 
99  public ZorbaXQItem(Item item) {
100  this.item = new Item(item);
101  this.itemType = new org.zorbaxquery.api.xqj.ZorbaXQItemType(this.item);
102  }
103 
104  public ZorbaXQItem(Item item, XQItemType itemType) {
105  this.item = new Item(item);
106  this.itemType = itemType;
107  }
108 
109  public ZorbaXQItem(javax.xml.xquery.XQItem item) throws XQException {
110  this.item = new Item(((ZorbaXQItem)item).getZorbaItem());
111  this.itemType = item.getItemType();
112  }
113 
114  /** \brief Close the item and release all the resources associated with this item.
115  *
116  * No method other than the isClosed or close method may be called once the item is closed. Calling close on an ZorbaXQItem object that is already closed has no effect.
117  *
118  * @throw XQException - if there is an error during closing the item
119  */
120  @Override
121  public void close() throws XQException {
122  if (!closed) {
123  item.close();
124  item.delete();
125  closed = true;
126  }
127  }
128 
129  /** \brief Checks if the item is closed.
130  *
131  * @return boolean true if the item is in a closed state, false otherwise
132  */
133  @Override
134  public boolean isClosed() {
135  return closed;
136  }
137 
138  /** \brief Gets the current item as a boolean.
139  *
140  * The current item must be an atomic value of type xs:boolean or a subtype.
141  *
142  * @return a boolean representing the current item
143  * @throw XQException - if (1) the conversion of the current item to a boolean fails, (2) if there are errors accessing the current item, (3) if the underlying sequence or item is in a closed state, or (4) in the case of forward only sequences, a get or write method was already invoked on the current item
144  */
145  @Override
146  public boolean getBoolean() throws XQException {
147  isClosedXQException();
148  if (itemType.getBaseType()!=XQItemType.XQBASETYPE_BOOLEAN) {
149  throw new XQException("Object is not boolean");
150  }
151  Boolean result;
152  try {
153  result = item.getBooleanValue();
154  } catch (Exception e) {
155  throw new XQException("Error getting boolean value" + e.getLocalizedMessage());
156  }
157  return result;
158  }
159 
160  /** \brief Gets the current item as a byte.
161  *
162  * The current item must be an atomic value of type xs:decimal or a subtype, and its value must be in the value space of byte.
163  *
164  * @return a byte representing the current item
165  * @throw XQException - if (1) the conversion of the current item to a byte fails, (2) if there are errors accessing the current item, (3) if the underlying sequence or item is in a closed state, or (4) in the case of forward only sequences, a get or write method was already invoked on the current item
166  */
167  @Override
168  public byte getByte() throws XQException {
169  isClosedXQException();
170  isDecimalXQException();
171  byte result = 0;
172  try {
173  if (itemType.getBaseType() == XQItemType.XQBASETYPE_BYTE) {
174  result = (byte) item.getIntValue();
175  } else {
176  result = Byte.parseByte(item.getStringValue());
177  }
178  } catch (Exception e) {
179  throw new XQException("Error getting byte value" + e.getLocalizedMessage());
180  }
181  return result;
182  }
183 
184  /** \brief Gets the current item as a double.
185  *
186  * The current item must be an atomic value of type xs:double or a subtype.
187  *
188  * @return a double representing the current item
189  * @throw XQException - if (1) the conversion of the current item to a double fails, (2) if there are errors accessing the current item, (3) if the underlying sequence or item is in a closed state, or (4) in the case of forward only sequences, a get or write method was already invoked on the current item
190  */
191  @Override
192  public double getDouble() throws XQException {
193  isClosedXQException();
194  isFloatXQException();
195  double result = 0;
196  try {
197  if (itemType.getBaseType() == XQItemType.XQBASETYPE_DOUBLE) {
198  result = item.getDoubleValue();
199  } else {
200  result = Double.parseDouble(item.getStringValue());
201  }
202  } catch (Exception e) {
203  throw new XQException("Error getting byte value" + e.getLocalizedMessage());
204  }
205  return result;
206  }
207 
208  /** \brief Gets the current item as a float.
209  *
210  * The current item must be an atomic value of type xs:float or a subtype.
211  *
212  * @return a float representing the current item
213  * @throw XQException - if (1) the conversion of the current item to a float fails, (2) if there are errors accessing the current item, (3) if the underlying sequence or item is in a closed state, or (4) in the case of forward only sequences, a get or write method was already invoked on the current item
214  */
215  @Override
216  public float getFloat() throws XQException {
217  isClosedXQException();
218  isFloatXQException();
219  float result = 0;
220  try {
221  if (itemType.getBaseType() == XQItemType.XQBASETYPE_FLOAT) {
222  result = (float)item.getDoubleValue();
223  } else {
224  result = Float.parseFloat(item.getStringValue());
225  }
226  } catch (Exception e) {
227  throw new XQException("Error getting byte value" + e.getLocalizedMessage());
228  }
229  return result;
230  }
231 
232  /** \brief Gets the current item as an int.
233  *
234  * Gets the current item as an int. The current item must be an atomic value of type xs:decimal or a subtype, and its value must be in the value space of int.
235  *
236  * @return an int representing the current item
237  * @throw XQException - if (1) the conversion of the current item to a int fails, (2) if there are errors accessing the current item, (3) if the underlying sequence or item is in a closed state, or (4) in the case of forward only sequences, a get or write method was already invoked on the current item
238  */
239  @Override
240  public int getInt() throws XQException {
241  isClosedXQException();
242  isDecimalXQException();
243  int result = 0;
244  try {
245  if (itemType.getBaseType() == XQItemType.XQBASETYPE_INT) {
246  result = item.getIntValue();
247  } else {
248  result = Integer.parseInt(item.getStringValue());
249  }
250  } catch (Exception e) {
251  throw new XQException("Error getting byte value" + e.getLocalizedMessage());
252  }
253  return result;
254  }
255 
256  /** \brief Gets the type of the item.
257  *
258  * On a forward only sequence this method can be called independent of any other get or write method. It will not raise an error if such method has been called already, nor will it affect subsequent invocations of any other get or write method.
259  *
260  * @return the type of the item
261  * @throw XQException - if (1) there are errors accessing the type of the item, or (2) the underlying sequence or item is in a closed state
262  */
263  @Override
264  public XQItemType getItemType() throws XQException {
265  isClosedXQException();
266  return itemType;
267  }
268 
269  /** \brief Gets the current item as a Java String.
270  *
271  * The current item must be an atomic value. This function casts the current item to an xs:string value according to the casting rules defined in 17.1.2 Casting to xs:string and xs:untypedAtomic, XQuery 1.0 and XPath 2.0 Functions and Operators, and then returns the value as a Java String.
272  *
273  * @return the string representation of the item
274  * @throw XQException - if (1) there are errors accessing the item's value, (2) the item is not an atomic value, (3) there is an error when casting the item to a string representation, (4) the underlying sequence or item is in a closed state, or (5) in the case of forward only sequences, a get or write method was already invoked on the current item
275  */
276  @Override
277  public String getAtomicValue() throws XQException {
278  isClosedXQException();
279  if (!item.isAtomic()) {
280  throw new XQException("Object is not atomic");
281  }
282  org.zorbaxquery.api.Item lItem = null;
283  try {
284  org.zorbaxquery.api.Iterator iterator = item.getAtomizationValue();
285  lItem = new Item(); // creating a new item to be filled by iterator
286  iterator.open();
287  iterator.next(lItem); // item CAN'T BE NULL
288  iterator.close();
289  } catch (Exception e) {
290  throw new XQException("Error getting atomic value: " + e.getLocalizedMessage());
291  }
292  return lItem.getStringValue();
293  }
294 
295  /** \brief Gets the current item as a long.
296  *
297  * The current item must be an atomic value of type xs:decimal or a subtype, and its value must be in the value space of long.
298  *
299  * @return a long representing the current item
300  * @throw XQException - if (1) the conversion of the current item to a long fails, (2) if there are errors accessing the current item, (3) if the underlying sequence or item is in a closed state, or (4) in the case of forward only sequences, a get or write method was already invoked on the current item
301  */
302  @Override
303  public long getLong() throws XQException {
304  isClosedXQException();
305  isDecimalXQException();
306  long result = 0;
307  try {
308  if (itemType.getBaseType() == XQItemType.XQBASETYPE_LONG) {
309  result = item.getLongValue();
310  } else {
311  result = Long.parseLong(item.getStringValue());
312  }
313  } catch (Exception e) {
314  throw new XQException("Error getting byte value" + e.getLocalizedMessage());
315  }
316  return result;
317  }
318 
319  /** \brief Gets the item as a DOM node.
320  *
321  * The current item must be a node. The type of the returned DOM node is governed by Table 7 - XQuery Node Types and Corresponding Java Object Types XQuery API for Java (XQJ) 1.0 The instance of the returned node is implementation dependent. The node may be a reference or a copy of the internal state of the item. It is advisable to make a copy of the node if the application plans to modify it.
322  *
323  * @return a DOM node representing the current item
324  * @throw XQException - if (1) if there are errors accessing the current item, (2) the current item is not a node, (3) if the underlying sequence or item is in a closed state, or (4) in the case of forward only sequences, a get or write method was already invoked on the current item
325  */
326  @Override
327  public Node getNode() throws XQException {
328  isClosedXQException();
329  if (!item.isNode()) {
330  throw new XQException("Object is not a node");
331  }
332  Node result = null;
333  InputStream inputStream = new ByteArrayInputStream(item.toString().getBytes());
334  try {
335  DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
336  DocumentBuilder db = dbf.newDocumentBuilder();
337  Document doc = db.newDocument();
338  Item nodeName = new Item();
339  item.getNodeName(nodeName);
340  switch (itemType.getItemKind()) {
341  case XQItemType.XQITEMKIND_ATTRIBUTE:
342  result = doc.createAttributeNS("", nodeName.getStringValue());
343  break;
344  case XQItemType.XQITEMKIND_COMMENT:
345  result = doc.createComment(item.getStringValue());
346  break;
347  case XQItemType.XQITEMKIND_DOCUMENT:
348  String tmpDoc = item.serialize();
349  if (tmpDoc.length()>0) {
350  result = db.parse(new InputSource(new StringReader(tmpDoc)));
351  } else {
352  result = doc; // empty doc
353  }
354  break;
355  case XQItemType.XQITEMKIND_ELEMENT:
356  Element e = doc.createElementNS("", nodeName.getStringValue());
357  Node text = doc.createTextNode(item.getStringValue());
358  e.appendChild(text);
359  result = e;
360  break;
361  case XQItemType.XQITEMKIND_PI:
362  String tmpPI = item.serialize().substring(2).split(" ")[0];
363  result = doc.createProcessingInstruction(tmpPI, item.getStringValue());
364  break;
365  case XQItemType.XQITEMKIND_TEXT:
366  result = doc.createTextNode(item.getStringValue());
367  break;
368  }
369  } catch (Exception ex) {
370  throw new XQException("Error converting Item to Node" + ex.getLocalizedMessage());
371  }
372 
373  return result;
374  }
375 
376  /** \brief Returns the URI for this item.
377  *
378  * If the item is a document node, then this method returns the absolute URI of the resource from which the document node was constructed. If the document URI is not available, then the empty string is returned. If the document URI is available, the returned value is the same as if fn:document-uri were evaluated on this document node. If the item is of a node kind other than document node, then the returned URI is implementation-defined.
379  * On a forward only sequence this method can be called independent of any other get or write method. It will not raise an error if such method has been called already, nor will it affect subsequent invocations of any other get or write method on the current item.
380  *
381  * @return the document URI for this document node or the empty string if not available. For other node kinds, the result is implementation-defined
382  * @throw XQException - if (1) if there are errors accessing the current item, (2) the current item is not a node, (3) if the underlying sequence or item is in a closed state
383  */
384  @Override
385  public URI getNodeUri() throws XQException {
386  isClosedXQException();
387  if (!item.isNode()) {
388  throw new XQException("Object is not a node");
389  }
390  URI result;
391  String namespace = "";
392  try {
393  Item type = new Item();
394  type = item.getType();
395  if (type.getStringValue().equalsIgnoreCase("xs:qname")) {
396  namespace = item.getNamespace();
397  } else {
398  StringPairVector bindings = item.getNamespaceBindings();
399  // Not using the full set, only the first binding
400  if (bindings.size()>0) {
401  StringPair pair = bindings.get(0);
402  namespace = pair.getFirst();
403  }
404  }
405  } catch (Exception ex) {
406  throw new XQException("Error getting Node URI: " + ex.getLocalizedMessage());
407  }
408  try {
409  result = new URI(namespace);
410  } catch (Exception ex) {
411  throw new XQException("Error getting Node URI: " + ex.getLocalizedMessage());
412  }
413  return result;
414  }
415 
416  /** \brief Gets the current item as an Object.
417  *
418  * The data type of the returned object will be the Java Object type as specified in 14.4 Mapping an XQuery Atomic Value to a Java Object Type and 14.5 Mapping an XQuery Node to a Java Object Type, XQuery API for Java (XQJ) 1.0.
419  *
420  * @return an object representing the current item
421  * @throw XQException - if (1) if there are errors accessing the current item, (2) if the underlying sequence or item is in a closed state, or (3) in the case of forward only sequences, a get or write method was already invoked on the current item
422  */
423  @Override
424  public Object getObject() throws XQException {
425  isClosedXQException();
426  Object result = null;
427  try {
428  if ((itemType.getItemKind()==XQItemType.XQITEMKIND_ATTRIBUTE) ||
429  (itemType.getItemKind()==XQItemType.XQITEMKIND_COMMENT) ||
430  (itemType.getItemKind()==XQItemType.XQITEMKIND_DOCUMENT) ||
431  (itemType.getItemKind()==XQItemType.XQITEMKIND_ELEMENT) ||
432  (itemType.getItemKind()==XQItemType.XQITEMKIND_PI) ||
433  (itemType.getItemKind()==XQItemType.XQITEMKIND_TEXT) ) {
434  result = this.getNode();
435  } else if (itemType.getItemKind()==XQItemType.XQITEMKIND_ATOMIC) {
436  //result = this.getNode();
437  DatatypeFactory factory = DatatypeFactory.newInstance();
438  switch (itemType.getBaseType()) {
439  /*
440  case ZorbaXQItemType.XQBASETYPE_ANYATOMICTYPE:
441  break;
442  case ZorbaXQItemType.XQBASETYPE_ANYSIMPLETYPE:
443  break;
444  case ZorbaXQItemType.XQBASETYPE_ANYTYPE:
445  break;
446  *
447  */
448  case XQItemType.XQBASETYPE_ANYURI:
449  result = item.getStringValue();
450  break;
451  case XQItemType.XQBASETYPE_BASE64BINARY:
452  result = item.serialize().getBytes();
453  break;
454  case XQItemType.XQBASETYPE_BOOLEAN:
455  result = item.getBooleanValue();
456  break;
457  case XQItemType.XQBASETYPE_BYTE:
458  result = new Byte(item.getStringValue());
459  break;
460  case XQItemType.XQBASETYPE_DATE:
461  case XQItemType.XQBASETYPE_DATETIME:
462  case XQItemType.XQBASETYPE_GDAY:
463  case XQItemType.XQBASETYPE_GMONTH:
464  case XQItemType.XQBASETYPE_GMONTHDAY:
465  case XQItemType.XQBASETYPE_GYEAR:
466  case XQItemType.XQBASETYPE_GYEARMONTH:
467  case XQItemType.XQBASETYPE_TIME:
468  result = factory.newXMLGregorianCalendar(item.getStringValue());
469  break;
470  case XQItemType.XQBASETYPE_DURATION:
471  result = factory.newDuration(item.getStringValue());
472  break;
473  case XQItemType.XQBASETYPE_DAYTIMEDURATION:
474  String tmpString = item.getStringValue();
475  result = factory.newDurationDayTime(tmpString);
476  break;
477  case XQItemType.XQBASETYPE_YEARMONTHDURATION:
478  result = factory.newDurationYearMonth(item.getStringValue());
479  break;
480  case XQItemType.XQBASETYPE_DECIMAL:
481  result = new BigDecimal(item.getStringValue());
482  break;
483  case XQItemType.XQBASETYPE_DOUBLE:
484  result = item.getDoubleValue();
485  break;
486  case XQItemType.XQBASETYPE_ENTITIES:
487  result = item.getStringValue();
488  break;
489  case XQItemType.XQBASETYPE_ENTITY:
490  result = item.getStringValue();
491  break;
492  case XQItemType.XQBASETYPE_FLOAT:
493  result = (float)(item.getDoubleValue());
494  break;
495  case XQItemType.XQBASETYPE_HEXBINARY:
496  result = item.getStringValue().getBytes();
497  break;
498  case XQItemType.XQBASETYPE_ID:
499  result = item.getStringValue();
500  break;
501  case XQItemType.XQBASETYPE_IDREF:
502  result = item.getStringValue();
503  break;
504  case XQItemType.XQBASETYPE_IDREFS:
505  result = item.getStringValue();
506  break;
507  case XQItemType.XQBASETYPE_INT:
508  result = item.getIntValue();
509  break;
510  case XQItemType.XQBASETYPE_LANGUAGE:
511  result = item.getStringValue();
512  break;
513  case XQItemType.XQBASETYPE_LONG:
514  result = item.getLongValue();
515  break;
516  case XQItemType.XQBASETYPE_NAME:
517  result = item.getStringValue();
518  break;
519  case XQItemType.XQBASETYPE_NCNAME:
520  result = item.serialize();
521  break;
522  case XQItemType.XQBASETYPE_NMTOKEN:
523  result = item.getStringValue();
524  break;
525  case XQItemType.XQBASETYPE_NMTOKENS:
526  result = item.getStringValue();
527  break;
528  case XQItemType.XQBASETYPE_INTEGER:
529  case XQItemType.XQBASETYPE_NEGATIVE_INTEGER:
530  case XQItemType.XQBASETYPE_POSITIVE_INTEGER:
531  case XQItemType.XQBASETYPE_NONNEGATIVE_INTEGER:
532  case XQItemType.XQBASETYPE_NONPOSITIVE_INTEGER:
533  case XQItemType.XQBASETYPE_UNSIGNED_LONG:
534  result = new BigInteger(item.getStringValue());
535  break;
536  case XQItemType.XQBASETYPE_NORMALIZED_STRING:
537  result = item.getStringValue();
538  break;
539  case XQItemType.XQBASETYPE_NOTATION:
540  result = item.getStringValue();
541  break;
542  case XQItemType.XQBASETYPE_QNAME:
543  result = new QName(item.getNamespace(), item.getLocalName(), item.getPrefix()) ;
544  break;
545  case XQItemType.XQBASETYPE_STRING:
546  result = item.getStringValue();
547  break;
548  case XQItemType.XQBASETYPE_TOKEN:
549  result = item.getStringValue();
550  break;
551  case XQItemType.XQBASETYPE_SHORT:
552  case XQItemType.XQBASETYPE_UNSIGNED_BYTE:
553  result = new Short(item.getStringValue());
554  break;
555  case XQItemType.XQBASETYPE_UNSIGNED_INT:
556  result = new Long(item.getStringValue());
557  break;
558  case XQItemType.XQBASETYPE_UNSIGNED_SHORT:
559  result = new Integer(item.getStringValue());
560  break;
561  case XQItemType.XQBASETYPE_UNTYPED:
562  result = item.getStringValue();
563  break;
564  case XQItemType.XQBASETYPE_UNTYPEDATOMIC:
565  result = item.getStringValue();
566  break;
567  }
568 
569  }
570  } catch (Exception e) {
571  throw new XQException("Error getting byte value: " + e.getLocalizedMessage());
572  }
573  return result;
574  }
575 
576  /** \brief Read the current item as an XMLStreamReader object.
577  *
578  * Read the current item as an XMLStreamReader object, as described in Section 12.1 Serializing an XDM instance into a StAX event stream (XMLStreamReader), XQuery API for Java (XQJ) 1.0. Note that the serialization process might fail, in which case a XQException is thrown. While the stream is being read, the application MUST NOT do any other concurrent operations on the underlying item or sequence. The operation on the stream is undefined if the underlying sequence is repositioned or the state of the underlying item or sequence is changed by concurrent operations.
579  *
580  * @return an XML reader object as XMLStreamReader
581  * @throw XQException - if (1) there are errors accessing the current item or the underlying sequence, (2) the underlying sequence or item is in a closed state, (3) in the case of a forward only sequence, a get or write method has already been invoked on the current item, or (4) in case of an error during serialization of the current item into a StAX event stream as defined in Section 12.1 Serializing an XDM instance into a StAX event stream (XMLStreamReader), XQuery API for Java (XQJ) 1.0
582  */
583  @Override
584  public XMLStreamReader getItemAsStream() throws XQException {
585  isClosedXQException();
586  XMLInputFactory factory = XMLInputFactory.newInstance();
587  XMLStreamReader result = null;
588  try {
589  result = factory.createXMLStreamReader(new StringReader(item.serialize()));
590  } catch (Exception ex) {
591  throw new XQException("Error creating XMLStreamReader: " + ex.getLocalizedMessage());
592  }
593  return result;
594  }
595 
596  /** \brief Serializes the current item according to the XSLT 2.0 and XQuery 1.0 serialization.
597  *
598  * Serialization parameters, which influence how serialization is performed, can be specified. Refer to the XSLT 2.0 and XQuery 1.0 serialization and Section 12 Serialization, XQuery API for Java (XQJ) 1.0 for more information.
599  *
600  * @param prprts - specifies the serialization parameters, null is considered equivalent to an empty Properties object
601  * @return the serialized representation of the item
602  * @throw XQException - if (1) there are errors accessing the current item or the underlying sequence, (2) the underlying sequence or item is in a closed state, (3) in the case of a forward only sequence, a get or write method has already been invoked on the current item, or (4) if there are errors during serialization
603  */
604  @Override
605  public String getItemAsString(Properties prprts) throws XQException {
606  isClosedXQException();
607  String result = null;
608  try {
609  SerializationOptions opts = new SerializationOptions();
610  if ((prprts!=null) && prprts.size()>0) {
611  for(String key : prprts.stringPropertyNames()) {
612  String value = prprts.getProperty(key);
613  opts.setSerializerOption(key, value);
614  }
615  }
616  result = item.serialize(opts).replace("&gt;", ">").replace("&lt;", "<");
617  } catch (Exception ex) {
618  throw new XQException("Error serializing item" + ex.getLocalizedMessage());
619  }
620  return result;
621  }
622 
623  /** \brief Gets the current item as a short.
624  *
625  * The current item must be an atomic value of type xs:decimal or a subtype, and its value must be in the value space of short.
626  *
627  * @return a short representing the current item
628  * @throw XQException - if (1) the conversion of the current item to a short fails, (2) if there are errors accessing the current item, (3) if the underlying sequence or item is in a closed state, or (4) in the case of forward only sequences, a get or write method was already invoked on the current item
629  */
630  @Override
631  public short getShort() throws XQException {
632  isClosedXQException();
633  isDecimalXQException();
634  short result;
635  try {
636  if (itemType.getBaseType() == XQItemType.XQBASETYPE_SHORT) {
637  result = (short) item.getIntValue();
638  } else {
639  result = Short.parseShort(item.getStringValue());
640  }
641  } catch (Exception ex) {
642  throw new XQException("Error getting short value: " + ex.getLocalizedMessage());
643  }
644  return result;
645  }
646 
647  /** \brief Checks if the item "matches" an item type.
648  *
649  * Checks if the item "matches" an item type, as defined in 2.5.4.2 Matching an Item Type and an Item, XQuery 1.0: An XML Query Language. You can use this method to first check the type of the result before calling the specific get methods.
650  *
651  * Example -
652  * \code{.java}
653  * ...
654  * ZorbaXQItemType strType = conn.createAtomicType(ZorbaXQItemType.XQBASETYPE_STRING);
655  * ZorbaXQItemType nodeType = conn.createNodeType();
656  *
657  * XQSequence result = preparedExpr.executeQuery();
658  * while (result.next())
659  * {
660  * // Generic check for node..
661  * if (result.instanceOf(nodeType))
662  * org.w3.dom.Node node = result.getNode();
663  * else if (result.instanceOf(strType))
664  * String str = result.getAtomicValue();
665  * }
666  *
667  *
668  * If either the type of the XQItemAccessor or the input ZorbaXQItemType is not a built-in type, then this method is allowed to raise exception if it can NOT determine the instanceOf relationship due to the lack of the access of the XML schema that defines the user defined schema types if the XQMetaData.isUserDefinedXMLSchemaTypeSupported() method returns false.
669  * Otherwise, this method must determine if the type of the XQItemAccessor is an instance of the input ZorbaXQItemType. Note even if isUserDefinedXMLSchemaTypeSupported() returns false, an XQJ implementation may still be able to determine the instanceOf relationship for certain cases involving user defined schema type. For example, if the type of an XQItemAccessor is of mySchema:hatSize sequence type and the input parameter ZorbaXQItemType is of item() sequence type, the return value for instanceOf relationship should always be true even though the XQJ implementation does not know the precise type information of mySchema:hatSize type defined in XML schema 'mySchema'.
670  * \endcode
671  * @param xqit - item type to match
672  * @return true if this item matches the input item type as defined in 2.5.4.2 Matching an Item Type and an Item, XQuery 1.0: An XML Query Language, and false if it does not
673  * @throw XQException - if (1) there are errors accessing the item's type, (2) if the underlying sequence or item is in a closed state, (3) if the implementation is unable to determine the schema definition of a user defined schema type, or (4) the type parameter is null
674  */
675  @Override
676  public boolean instanceOf(XQItemType xqit) throws XQException {
677  isClosedXQException();
678  return itemType.equals(xqit);
679  }
680 
681  /** \brief Serializes the current item to a Writer.
682  *
683  * Serializes the current item to a Writer according to XSLT 2.0 and XQuery 1.0 serialization. Serialization parameters, which influence how serialization is performed, can be specified. Refer to the XSLT 2.0 and XQuery 1.0 serialization and Section 12 Serialization, XQuery API for Java (XQJ) 1.0 for more information.
684  *
685  * @param out - the output stream into which the current item is to be serialized
686  * @param prprts - specifies the serialization parameters, null is considered equivalent to an empty Properties object
687  * @throw XQException - if (1) there are errors accessing the current item or the underlying sequence, (2) the underlying sequence or item is in a closed state, (3) in the case of a forward only sequence, a get or write method has already been invoked on the current item, (4) if there are errors during serialization, or (5) the os parameter is null
688  */
689  @Override
690  public void writeItem(OutputStream out, Properties prprts) throws XQException {
691  isClosedXQException();
692  isNullXQException(out);
693  isNullXQException(prprts);
694  try {
695  SerializationOptions opts = new SerializationOptions();
696  if ((prprts!=null) && prprts.size()>0) {
697  for(String key : prprts.stringPropertyNames()) {
698  String value = prprts.getProperty(key);
699  opts.setSerializerOption(key, value);
700  }
701  }
702  ZorbaOutputWrapper OStream = new ZorbaOutputWrapper(out);
703  item.serializeToStream(OStream);
704  } catch (Exception ex) {
705  throw new XQException("Error writing on stream: " + ex.getLocalizedMessage());
706  }
707  }
708 
709  /** \brief Serializes the current item to a Writer.
710  *
711  * Serializes the current item to a Writer according to XSLT 2.0 and XQuery 1.0 serialization. Serialization parameters, which influence how serialization is performed, can be specified. Refer to the XSLT 2.0 and XQuery 1.0 serialization and Section 12 Serialization, XQuery API for Java (XQJ) 1.0 for more information.
712  *
713  * Warning: When outputting to a Writer, make sure the writer's encoding matches the encoding parameter if specified as a property or the default encoding.
714  * @param writer - the output stream into which the current item is to be serialized
715  * @param prprts - specifies the serialization parameters, null is considered equivalent to an empty Properties object
716  * @throw XQException - if (1) there are errors accessing the current item or the underlying sequence, (2) the underlying sequence or item is in a closed state, (3) in the case of a forward only sequence, a get or write method has already been invoked on the current item, (4) if there are errors during serialization, or (5) the os parameter is null
717  */
718  @Override
719  public void writeItem(Writer writer, Properties prprts) throws XQException {
720  isClosedXQException();
721  isNullXQException(writer);
722  isNullXQException(prprts);
723  try {
724  SerializationOptions opts = new SerializationOptions();
725  if ((prprts!=null) && prprts.size()>0) {
726  for(String key : prprts.stringPropertyNames()) {
727  String value = prprts.getProperty(key);
728  opts.setSerializerOption(key, value);
729  }
730  }
731  ZorbaWriterWrapper OStream = new ZorbaWriterWrapper(writer);
732  item.serializeToStream(OStream);
733  writer.write(item.serialize(opts));
734  } catch (Exception ex) {
735  throw new XQException("Error sending to writer: " + ex.getLocalizedMessage());
736  }
737  }
738 
739  /** \brief Writes the current item to a SAX handler.
740  *
741  * Writes the current item to a SAX handler, as described in in Section 12.2 Serializing an XDM instance into a SAX event stream, XQuery API for Java (XQJ) 1.0. Note that the serialization process might fail, in which case a XQException is thrown. The specified org.xml.sax.ContentHandler can optionally implement the org.xml.sax.LexicalHandler interface. An implementation must check if the specified ContentHandler implements LexicalHandler. If the handler is a LexicalHandler comment nodes are reported, otherwise they will be silently ignored.
742  *
743  * @param ch - the SAX content handler, optionally a lexical handler
744  * @throw XQException - if (1) there are errors accessing the current item or the underlying sequence, (2) the underlying sequence or item is in a closed state, (3) in the case of a forward only sequence, a get or write method has already been invoked on the current item, (4) in case of an error while serializing the XDM instance into a SAX event stream, or (5) the saxhdlr parameter is null
745  */
746  @Override
747  public void writeItemToSAX(ContentHandler ch) throws XQException {
748  isClosedXQException();
749  isNullXQException(ch);
750  try {
751  AttributesImpl attributes = new AttributesImpl();
752  Iterator attr = item.getAttributes();
753  attr.open();
754  Item attribute = new Item();
755  while (attr.next(attribute)) {
756  attributes.addAttribute(attribute.getNamespace(), attribute.getLocalName(), "", attribute.getType().getStringValue(), attribute.getStringValue());
757  }
758  attribute.close();
759  attr.close();
760  attr.delete();
761  //attribute.delete();
762  String namespace = "";
763  if (itemType.getBaseType() != XQItemType.XQBASETYPE_ANYTYPE){
764  namespace = item.getNamespace();
765  }
766  Item name = new Item();
767  item.getNodeName(name);
768  String nodeName = name.getStringValue();
769  name.close();
770  //name.delete();
771  char [] content = item.getStringValue().toCharArray();
772 
773  ch.startElement(namespace, nodeName , "", attributes);
774  ch.characters(content, 0, content.length);
775  ch.endElement(namespace, nodeName, "");
776  } catch (Exception ex) {
777  throw new XQException("Error writing item to SAX: " + ex.getLocalizedMessage());
778  }
779  }
780 
781  /** \brief Writes the current item to a Result.
782  *
783  * First the item is normalized as described in XSLT 2.0 and XQuery 1.0 serialization. Subsequently it is serialized to the Result object.
784  * Note that the normalization process can fail, in which case an XQException is thrown. An XQJ implementation must at least support the following implementations:
785  * - javax.xml.transform.dom.DOMResult
786  * - javax.xml.transform.sax.SAXResult
787  * - javax.xml.transform.stream.StreamResult
788  *
789  * @param result - the result object into which the item is to be serialized
790  * @throw XQException - if (1) there are errors accessing the current item or the underlying sequence, (2) the underlying sequence or item is in a closed state, (3) in the case of a forward only sequence, a get or write method has already been invoked on the current item, (4) in case of an error while serializing the current item into the Result object, or (5) the result parameter is null
791  */
792  @Override
793  public void writeItemToResult(Result result) throws XQException {
794  isClosedXQException();
795  isNullXQException(result);
796  try {
797  Source xmlSource = new DOMSource(getNode());
798  TransformerFactory transformerFactory = TransformerFactory.newInstance();
799  Transformer transformer;
800  transformer = transformerFactory.newTransformer();
801  transformer.setOutputProperty("indent", "yes");
802  transformer.transform(xmlSource, result);
803  } catch (Exception ex) {
804  throw new XQException ("Error serializing to javax.xml.transform.Result");
805  }
806  }
807 
808  private void isClosedXQException() throws XQException {
809  if (closed) {
810  throw new XQException("This connection is closed");
811  }
812  }
813 
814  private void isNullXQException(Object value) throws XQException {
815  if (value==null) {
816  throw new XQException("Parameter shouldn't be null");
817  }
818  }
819 
820  private void isDecimalXQException() throws XQException {
821  switch (itemType.getBaseType()) {
822  case XQItemType.XQBASETYPE_DECIMAL:
823  case XQItemType.XQBASETYPE_BYTE:
824  case XQItemType.XQBASETYPE_INT:
825  case XQItemType.XQBASETYPE_INTEGER:
826  case XQItemType.XQBASETYPE_LONG:
827  case XQItemType.XQBASETYPE_NEGATIVE_INTEGER:
828  case XQItemType.XQBASETYPE_NONNEGATIVE_INTEGER:
829  case XQItemType.XQBASETYPE_NONPOSITIVE_INTEGER:
830  case XQItemType.XQBASETYPE_POSITIVE_INTEGER:
831  case XQItemType.XQBASETYPE_SHORT:
832  case XQItemType.XQBASETYPE_UNSIGNED_LONG:
833  case XQItemType.XQBASETYPE_UNSIGNED_INT:
834  case XQItemType.XQBASETYPE_UNSIGNED_SHORT:
835  case XQItemType.XQBASETYPE_UNSIGNED_BYTE:
836  break;
837  default:
838  throw new XQException("Object is not xs:decimal or a derivate");
839  }
840  }
841 
842  private void isFloatXQException() throws XQException {
843  if (! ((itemType.getBaseType()==XQItemType.XQBASETYPE_FLOAT) ||
844  (itemType.getBaseType()==XQItemType.XQBASETYPE_DOUBLE)) )
845  {
846  throw new XQException("Object is not xs:decimal or a derivate");
847  }
848  }
849 }