001: package net.sf.saxon.query;
002:
003: import net.sf.saxon.event.Receiver;
004: import net.sf.saxon.event.SequenceReceiver;
005: import net.sf.saxon.om.Item;
006: import net.sf.saxon.om.NamePool;
007: import net.sf.saxon.om.NamespaceConstant;
008: import net.sf.saxon.om.NodeInfo;
009: import net.sf.saxon.trans.XPathException;
010: import net.sf.saxon.type.AtomicType;
011: import net.sf.saxon.value.AtomicValue;
012: import net.sf.saxon.style.StandardNames;
013:
014: /**
015: * This class can be used in a push pipeline: it accepts any sequence as input, and generates
016: * a document in which the items of the sequence are wrapped by elements containing information about
017: * the types of the items in the input sequence.
018: */
019:
020: public class SequenceWrapper extends SequenceReceiver {
021:
022: public static final String RESULT_NS = QueryResult.RESULT_NS;
023:
024: private Receiver out;
025: private int depth = 0;
026:
027: private int resultSequence;
028: private int resultDocument;
029: private int resultElement;
030: private int resultAttribute;
031: private int resultText;
032: private int resultComment;
033: private int resultPI;
034: private int resultNamespace;
035: private int resultAtomicValue;
036: private int xsiType;
037:
038: public SequenceWrapper(Receiver destination) {
039: this .out = destination;
040: setPipelineConfiguration(destination.getPipelineConfiguration());
041: }
042:
043: public void open() throws XPathException {
044:
045: NamePool pool = getNamePool();
046:
047: resultSequence = pool.allocate("result", RESULT_NS, "sequence");
048: resultDocument = pool.allocate("result", RESULT_NS, "document");
049: resultElement = pool.allocate("result", RESULT_NS, "element");
050: resultAttribute = pool.allocate("result", RESULT_NS,
051: "attribute");
052: resultText = pool.allocate("result", RESULT_NS, "text");
053: resultComment = pool.allocate("result", RESULT_NS, "comment");
054: resultPI = pool.allocate("result", RESULT_NS,
055: "processing-instruction");
056: resultNamespace = pool.allocate("result", RESULT_NS,
057: "namespace");
058: resultAtomicValue = pool.allocate("result", RESULT_NS,
059: "atomic-value");
060: xsiType = pool.allocate("xsi",
061: NamespaceConstant.SCHEMA_INSTANCE, "type");
062:
063: out.open();
064: out.startDocument(0);
065:
066: out.startElement(resultSequence, StandardNames.XDT_UNTYPED, 0,
067: 0);
068: out.namespace(pool.allocateNamespaceCode("result", RESULT_NS),
069: 0);
070: out.namespace(pool.allocateNamespaceCode("xs",
071: NamespaceConstant.SCHEMA), 0);
072: out.namespace(pool.allocateNamespaceCode("xsi",
073: NamespaceConstant.SCHEMA_INSTANCE), 0);
074: out.startContent();
075:
076: }
077:
078: /**
079: * Start of a document node.
080: */
081:
082: public void startDocument(int properties) throws XPathException {
083: out.startElement(resultDocument, StandardNames.XDT_UNTYPED, 0,
084: 0);
085: out.startContent();
086: depth++;
087: }
088:
089: /**
090: * Notify the end of a document node
091: */
092:
093: public void endDocument() throws XPathException {
094: out.endElement();
095: depth--;
096: }
097:
098: /**
099: * Notify the start of an element
100: *
101: * @param nameCode integer code identifying the name of the element within the name pool.
102: * @param typeCode integer code identifying the element's type within the name pool.
103: * @param properties properties of the element node
104: */
105:
106: public void startElement(int nameCode, int typeCode,
107: int locationId, int properties) throws XPathException {
108: if (depth++ == 0) {
109: out.startElement(resultElement, StandardNames.XDT_UNTYPED,
110: 0, 0);
111: out.startContent();
112: }
113: out.startElement(nameCode, typeCode, locationId, properties);
114: }
115:
116: /**
117: * End of element
118: */
119:
120: public void endElement() throws XPathException {
121: out.endElement();
122: if (--depth == 0) {
123: out.endElement(); // close the wrapping element
124: }
125: }
126:
127: /**
128: * Notify an attribute. Attributes are notified after the startElement event, and before any
129: * children. Namespaces and attributes may be intermingled.
130: *
131: * @param nameCode The name of the attribute, as held in the name pool
132: * @param typeCode The type of the attribute, as held in the name pool
133: * @param properties Bit significant value. The following bits are defined:
134: * <dd>DISABLE_ESCAPING</dd> <dt>Disable escaping for this attribute</dt>
135: * <dd>NO_SPECIAL_CHARACTERS</dd> <dt>Attribute value contains no special characters</dt>
136: * @throws IllegalStateException: attempt to output an attribute when there is no open element
137: * start tag
138: */
139:
140: public void attribute(int nameCode, int typeCode,
141: CharSequence value, int locationId, int properties)
142: throws XPathException {
143: if (depth == 0) {
144: out.startElement(resultAttribute,
145: StandardNames.XDT_UNTYPED, 0, 0);
146: out.attribute(nameCode, typeCode, value, locationId,
147: properties);
148: out.startContent();
149: out.endElement();
150: } else {
151: out.attribute(nameCode, typeCode, value, locationId,
152: properties);
153: }
154: }
155:
156: /**
157: * Notify a namespace. Namespaces are notified <b>after</b> the startElement event, and before
158: * any children for the element. The namespaces that are reported are only required
159: * to include those that are different from the parent element; however, duplicates may be reported.
160: * A namespace must not conflict with any namespaces already used for element or attribute names.
161: *
162: * @param namespaceCode an integer: the top half is a prefix code, the bottom half a URI code.
163: * These may be translated into an actual prefix and URI using the name pool. A prefix code of
164: * zero represents the empty prefix (that is, the default namespace). A URI code of zero represents
165: * a URI of "", that is, a namespace undeclaration.
166: * @throws IllegalStateException: attempt to output a namespace when there is no open element
167: * start tag
168: */
169:
170: public void namespace(int namespaceCode, int properties)
171: throws XPathException {
172: if (depth == 0) {
173: out.startElement(resultNamespace,
174: StandardNames.XDT_UNTYPED, 0, 0);
175: out.namespace(namespaceCode, properties);
176: out.startContent();
177: out.endElement();
178: } else {
179: out.namespace(namespaceCode, properties);
180: }
181: }
182:
183: /**
184: * Character data
185: */
186:
187: public void characters(CharSequence chars, int locationId,
188: int properties) throws XPathException {
189: if (depth == 0) {
190: out.startElement(resultText, StandardNames.XDT_UNTYPED, 0,
191: 0);
192: out.startContent();
193: out.characters(chars, locationId, properties);
194: out.endElement();
195: } else {
196: out.characters(chars, locationId, properties);
197: }
198: }
199:
200: /**
201: * Output a comment
202: */
203:
204: public void comment(CharSequence chars, int locationId,
205: int properties) throws XPathException {
206: if (depth == 0) {
207: out.startElement(resultComment, StandardNames.XDT_UNTYPED,
208: 0, 0);
209: out.startContent();
210: out.comment(chars, locationId, properties);
211: out.endElement();
212: } else {
213: out.comment(chars, locationId, properties);
214: }
215: }
216:
217: /**
218: * Processing Instruction
219: */
220:
221: public void processingInstruction(String target, CharSequence data,
222: int locationId, int properties) throws XPathException {
223: if (depth == 0) {
224: out.startElement(resultPI, StandardNames.XDT_UNTYPED, 0, 0);
225: out.startContent();
226: out.processingInstruction(target, data, locationId,
227: properties);
228: out.endElement();
229: } else {
230: out.processingInstruction(target, data, locationId,
231: properties);
232: }
233: }
234:
235: /**
236: * Output an item (atomic value or node) to the sequence
237: */
238:
239: public void append(Item item, int locationId, int copyNamespaces)
240: throws XPathException {
241: if (item instanceof AtomicValue) {
242: final NamePool pool = getNamePool();
243: out.startElement(resultAtomicValue,
244: StandardNames.XDT_UNTYPED, 0, 0);
245: AtomicType type = (AtomicType) ((AtomicValue) item)
246: .getItemType(pool.getTypeHierarchy());
247: int nameCode = type.getNameCode();
248: String prefix = pool.getPrefix(nameCode);
249: String localName = pool.getLocalName(nameCode);
250: String uri = pool.getURI(nameCode);
251: if (prefix.equals("")) {
252: prefix = pool.suggestPrefixForURI(uri);
253: if (prefix == null) {
254: prefix = "p" + uri.hashCode();
255: }
256: }
257: int nscode = pool.allocateNamespaceCode(prefix, uri);
258: String displayName = prefix + ':' + localName;
259: out.namespace(nscode, 0);
260: out.attribute(xsiType, StandardNames.XDT_UNTYPED_ATOMIC,
261: displayName, 0, 0);
262: out.startContent();
263: out.characters(item.getStringValue(), 0, 0);
264: out.endElement();
265: } else {
266: ((NodeInfo) item).copy(this , NodeInfo.ALL_NAMESPACES, true,
267: locationId);
268: }
269: }
270:
271: /**
272: * Notify the start of the content, that is, the completion of all attributes and namespaces.
273: * Note that the initial receiver of output from XSLT instructions will not receive this event,
274: * it has to detect it itself. Note that this event is reported for every element even if it has
275: * no attributes, no namespaces, and no content.
276: */
277:
278: public void startContent() throws XPathException {
279: out.startContent();
280: }
281:
282: /**
283: * Notify the end of the event stream
284: */
285:
286: public void close() throws XPathException {
287: out.endElement(); // close the result:sequence element
288: out.endDocument();
289: out.close();
290: }
291:
292: }
293:
294: //
295: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
296: // you may not use this file except in compliance with the License. You may obtain a copy of the
297: // License at http://www.mozilla.org/MPL/
298: //
299: // Software distributed under the License is distributed on an "AS IS" basis,
300: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
301: // See the License for the specific language governing rights and limitations under the License.
302: //
303: // The Original Code is: all this file.
304: //
305: // The Initial Developer of the Original Code is Michael H. Kay.
306: //
307: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
308: //
309: // Contributor(s): none.
310: //
|