001: package net.sf.saxon.pull;
002:
003: import net.sf.saxon.event.Receiver;
004: import net.sf.saxon.event.SequenceReceiver;
005: import net.sf.saxon.om.AttributeCollection;
006: import net.sf.saxon.om.NamespaceDeclarations;
007: import net.sf.saxon.om.Orphan;
008: import net.sf.saxon.trans.XPathException;
009: import net.sf.saxon.type.Type;
010:
011: /**
012: * PullPushTee is a pass-through filter class that links one PullProvider to another PullProvider
013: * in a pipeline, copying all events that are read into a push pipeline, supplied in the form
014: * of a Receiver.
015: *
016: * <p>This class can be used to insert a schema validator into a pull pipeline, since Saxon's schema
017: * validation is push-based. It could also be used to insert a serializer into the pipeline, allowing
018: * the XML document being "pulled" to be displayed for diagnostic purposes.</p>
019: */
020:
021: public class PullPushTee extends PullFilter {
022:
023: private Receiver branch;
024: boolean previousAtomic = false;
025:
026: /**
027: * Create a PullPushTee
028: * @param base the PullProvider to which requests are to be passed
029: * @param branch the Receiver to which all events are to be copied, as "push" events
030: */
031:
032: public PullPushTee(PullProvider base, Receiver branch)
033: throws XPathException {
034: super (base);
035: this .branch = branch;
036: branch.open();
037: }
038:
039: /**
040: * Get the Receiver to which events are being tee'd.
041: */
042:
043: public Receiver getReceiver() {
044: return branch;
045: }
046:
047: /**
048: * Get the next event. This implementation gets the next event from the underlying PullProvider,
049: * copies it to the branch Receiver, and then returns the event to the caller.
050: *
051: * @return an integer code indicating the type of event. The code
052: * {@link #END_OF_INPUT} is returned at the end of the sequence.
053: */
054:
055: public int next() throws XPathException {
056: currentEvent = super .next();
057: copyEvent(currentEvent);
058: return currentEvent;
059: }
060:
061: /**
062: * Copy a pull event to a Receiver
063: */
064:
065: private void copyEvent(int event) throws XPathException {
066: PullProvider in = getUnderlyingProvider();
067: Receiver out = branch;
068: switch (event) {
069: case START_DOCUMENT:
070: out.startDocument(0);
071: break;
072:
073: case START_ELEMENT:
074: out.startElement(in.getNameCode(), in.getTypeAnnotation(),
075: 0, 0);
076:
077: NamespaceDeclarations decl = in.getNamespaceDeclarations();
078: for (int i = 0; i < decl.getLength(); i++) {
079: out.namespace(decl.getNamespaceCode(i), 0);
080: }
081:
082: AttributeCollection atts = in.getAttributes();
083: for (int i = 0; i < atts.getLength(); i++) {
084: out.attribute(atts.getNameCode(i), atts
085: .getTypeAnnotation(i), atts.getValue(i), 0,
086: atts.getProperties(i));
087: }
088:
089: out.startContent();
090: break;
091:
092: case TEXT:
093:
094: out.characters(in.getStringValue(), 0, 0);
095: break;
096:
097: case COMMENT:
098:
099: out.comment(in.getStringValue(), 0, 0);
100: break;
101:
102: case PROCESSING_INSTRUCTION:
103:
104: out.processingInstruction(in.getPipelineConfiguration()
105: .getConfiguration().getNamePool().getLocalName(
106: in.getNameCode()), in.getStringValue(), 0,
107: 0);
108: break;
109:
110: case END_ELEMENT:
111:
112: out.endElement();
113: break;
114:
115: case END_DOCUMENT:
116: out.endDocument();
117: break;
118:
119: case END_OF_INPUT:
120: in.close();
121: out.close();
122: break;
123:
124: case ATOMIC_VALUE:
125: if (out instanceof SequenceReceiver) {
126: ((SequenceReceiver) out).append(super .getAtomicValue(),
127: 0, 0);
128: break;
129: } else {
130: if (previousAtomic) {
131: out.characters(" ", 0, 0);
132: }
133: CharSequence chars = in.getStringValue();
134: out.characters(chars, 0, 0);
135: break;
136: }
137:
138: case ATTRIBUTE:
139: if (out instanceof SequenceReceiver) {
140: Orphan o = new Orphan(in.getPipelineConfiguration()
141: .getConfiguration());
142: o.setNameCode(getNameCode());
143: o.setNodeKind(Type.ATTRIBUTE);
144: o.setStringValue(getStringValue());
145: ((SequenceReceiver) out).append(o, 0, 0);
146: break;
147: } else {
148: out.attribute(getNameCode(), getTypeAnnotation(),
149: getStringValue(), 0, 0);
150: break;
151: //throw new DynamicError("Cannot serialize a free-standing attribute node");
152: }
153:
154: case NAMESPACE:
155: if (out instanceof SequenceReceiver) {
156: Orphan o = new Orphan(in.getPipelineConfiguration()
157: .getConfiguration());
158: o.setNameCode(getNameCode());
159: o.setNodeKind(Type.NAMESPACE);
160: o.setStringValue(getStringValue());
161: ((SequenceReceiver) out).append(o, 0, 0);
162: break;
163: } else {
164: int nsCode = getNamePool().getNamespaceCode(
165: getNameCode());
166: out.namespace(nsCode, 0);
167: break;
168: //throw new DynamicError("Cannot serialize a free-standing namespace node");
169: }
170:
171: default:
172: throw new UnsupportedOperationException("" + event);
173:
174: }
175: previousAtomic = (event == ATOMIC_VALUE);
176: }
177: }
178:
179: //
180: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
181: // you may not use this file except in compliance with the License. You may obtain a copy of the
182: // License at http://www.mozilla.org/MPL/
183: //
184: // Software distributed under the License is distributed on an "AS IS" basis,
185: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
186: // See the License for the specific language governing rights and limitations under the License.
187: //
188: // The Original Code is: all this file.
189: //
190: // The Initial Developer of the Original Code is Michael H. Kay.
191: //
192: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
193: //
194: // Contributor(s): none.
195: //
|