001: package net.sf.saxon.instruct;
002:
003: import net.sf.saxon.Controller;
004: import net.sf.saxon.event.Receiver;
005: import net.sf.saxon.event.ReceiverOptions;
006: import net.sf.saxon.event.SequenceReceiver;
007: import net.sf.saxon.expr.*;
008: import net.sf.saxon.om.*;
009: import net.sf.saxon.style.StandardNames;
010: import net.sf.saxon.tinytree.TinyBuilder;
011: import net.sf.saxon.trans.DynamicError;
012: import net.sf.saxon.trans.XPathException;
013: import net.sf.saxon.type.ItemType;
014:
015: import java.io.PrintStream;
016: import java.util.Iterator;
017:
018: /**
019: * A saxon:doctype element in the stylesheet.
020: */
021:
022: public class Doctype extends Instruction {
023:
024: private Expression content;
025:
026: public Doctype(Expression content) {
027: this .content = content;
028: }
029:
030: /**
031: * Simplify an expression. This performs any static optimization (by rewriting the expression
032: * as a different expression). The default implementation does nothing.
033: * @return the simplified expression
034: * @throws net.sf.saxon.trans.XPathException
035: * if an error is discovered during expression rewriting
036: */
037:
038: public Expression simplify(StaticContext env) throws XPathException {
039: content = content.simplify(env);
040: return this ;
041: }
042:
043: public Expression typeCheck(StaticContext env,
044: ItemType contextItemType) throws XPathException {
045: content = content.typeCheck(env, contextItemType);
046: adoptChildExpression(content);
047: return this ;
048: }
049:
050: public Expression optimize(Optimizer opt, StaticContext env,
051: ItemType contextItemType) throws XPathException {
052: content = content.optimize(opt, env, contextItemType);
053: adoptChildExpression(content);
054: return this ;
055: }
056:
057: /**
058: * Get the immediate sub-expressions of this expression. Default implementation
059: * returns a zero-length array, appropriate for an expression that has no
060: * sub-expressions.
061: *
062: * @return an iterator containing the sub-expressions of this expression
063: */
064:
065: public Iterator iterateSubExpressions() {
066: return new MonoIterator(content);
067: }
068:
069: /**
070: * Handle promotion offers, that is, non-local tree rewrites.
071: * @param offer The type of rewrite being offered
072: * @throws XPathException
073: */
074:
075: protected void promoteInst(PromotionOffer offer)
076: throws XPathException {
077: content = doPromotion(content, offer);
078: }
079:
080: /**
081: * Determine whether this instruction creates new nodes.
082: * This implementation returns true.
083: */
084:
085: public final boolean createsNewNodes() {
086: return true;
087: }
088:
089: /**
090: * Get the name of this instruction for diagnostic and tracing purposes
091: */
092:
093: public int getInstructionNameCode() {
094: return StandardNames.SAXON_DOCTYPE;
095: }
096:
097: public TailCall processLeavingTail(XPathContext context)
098: throws XPathException {
099: Controller controller = context.getController();
100: XPathContext c2 = context.newMinorContext();
101: c2.setOrigin(this );
102: SequenceReceiver out = c2.getReceiver();
103: TinyBuilder builder = new TinyBuilder();
104: Receiver receiver = builder;
105: receiver.setPipelineConfiguration(controller
106: .makePipelineConfiguration());
107: receiver.open();
108: receiver.startDocument(0);
109: c2.changeOutputDestination(null, receiver, false,
110: Validation.PRESERVE, null);
111: content.process(c2);
112: receiver.endDocument();
113: receiver.close();
114: DocumentInfo dtdRoot = (DocumentInfo) builder.getCurrentRoot();
115:
116: SequenceIterator children = dtdRoot.iterateAxis(Axis.CHILD);
117: NodeInfo docType = (NodeInfo) children.next();
118: if (docType == null
119: || !("doctype".equals(docType.getLocalPart()))) {
120: DynamicError e = new DynamicError(
121: "saxon:doctype instruction must contain dtd:doctype");
122: e.setXPathContext(context);
123: throw e;
124: }
125: String name = Navigator.getAttributeValue(docType, "", "name");
126: String system = Navigator.getAttributeValue(docType, "",
127: "system");
128: String publicid = Navigator.getAttributeValue(docType, "",
129: "public");
130:
131: if (name == null) {
132: DynamicError e = new DynamicError(
133: "dtd:doctype must have a name attribute");
134: e.setXPathContext(context);
135: throw e;
136: }
137:
138: write(out, "<!DOCTYPE " + name + ' ');
139: if (system != null) {
140: if (publicid != null) {
141: write(out, "PUBLIC \"" + publicid + "\" \"" + system
142: + '\"');
143: } else {
144: write(out, "SYSTEM \"" + system + '\"');
145: }
146: }
147:
148: boolean openSquare = false;
149: children = docType.iterateAxis(Axis.CHILD);
150:
151: NodeInfo child = (NodeInfo) children.next();
152: if (child != null) {
153: write(out, " [");
154: openSquare = true;
155: }
156:
157: while (child != null) {
158: String localname = child.getLocalPart();
159:
160: if ("element".equals(localname)) {
161: String elname = Navigator.getAttributeValue(child, "",
162: "name");
163: String content = Navigator.getAttributeValue(child, "",
164: "content");
165: if (elname == null) {
166: DynamicError e = new DynamicError(
167: "dtd:element must have a name attribute");
168: e.setXPathContext(context);
169: throw e;
170: }
171: if (content == null) {
172: DynamicError e = new DynamicError(
173: "dtd:element must have a content attribute");
174: e.setXPathContext(context);
175: throw e;
176: }
177: write(out, "\n <!ELEMENT " + elname + ' ' + content
178: + '>');
179:
180: } else if (localname.equals("attlist")) {
181: String elname = Navigator.getAttributeValue(child, "",
182: "element");
183: if (elname == null) {
184: DynamicError e = new DynamicError(
185: "dtd:attlist must have an attribute named 'element'");
186: e.setXPathContext(context);
187: throw e;
188: }
189: write(out, "\n <!ATTLIST " + elname + ' ');
190:
191: SequenceIterator attributes = child
192: .iterateAxis(Axis.CHILD);
193: while (true) {
194: NodeInfo attDef = (NodeInfo) attributes.next();
195: if (attDef == null) {
196: break;
197: }
198:
199: if ("attribute".equals(attDef.getLocalPart())) {
200:
201: String atname = Navigator.getAttributeValue(
202: attDef, "", "name");
203: String type = Navigator.getAttributeValue(
204: attDef, "", "type");
205: String value = Navigator.getAttributeValue(
206: attDef, "", "value");
207: if (atname == null) {
208: DynamicError e = new DynamicError(
209: "dtd:attribute must have a name attribute");
210: e.setXPathContext(context);
211: throw e;
212: }
213: if (type == null) {
214: DynamicError e = new DynamicError(
215: "dtd:attribute must have a type attribute");
216: e.setXPathContext(context);
217: throw e;
218: }
219: if (value == null) {
220: DynamicError e = new DynamicError(
221: "dtd:attribute must have a value attribute");
222: e.setXPathContext(context);
223: throw e;
224: }
225: write(out, "\n " + atname + ' ' + type + ' '
226: + value);
227: } else {
228: DynamicError e = new DynamicError(
229: "Unrecognized element within dtd:attlist");
230: e.setXPathContext(context);
231: throw e;
232: }
233: }
234: write(out, ">");
235:
236: } else if (localname.equals("entity")) {
237:
238: String entname = Navigator.getAttributeValue(child, "",
239: "name");
240: String parameter = Navigator.getAttributeValue(child,
241: "", "parameter");
242: String esystem = Navigator.getAttributeValue(child, "",
243: "system");
244: String epublicid = Navigator.getAttributeValue(child,
245: "", "public");
246: String notation = Navigator.getAttributeValue(child,
247: "", "notation");
248:
249: if (entname == null) {
250: DynamicError e = new DynamicError(
251: "dtd:entity must have a name attribute");
252: e.setXPathContext(context);
253: throw e;
254: }
255:
256: // we could do a lot more checking now...
257:
258: write(out, "\n <!ENTITY ");
259: if ("yes".equals(parameter)) {
260: write(out, "% ");
261: }
262: write(out, entname + ' ');
263: if (esystem != null) {
264: if (epublicid != null) {
265: write(out, "PUBLIC \"" + epublicid + "\" \""
266: + esystem + "\" ");
267: } else {
268: write(out, "SYSTEM \"" + esystem + "\" ");
269: }
270: }
271: if (notation != null) {
272: write(out, "NDATA " + notation + ' ');
273: }
274:
275: SequenceIterator contents = child
276: .iterateAxis(Axis.CHILD);
277: while (true) {
278: NodeInfo content = (NodeInfo) contents.next();
279: if (content == null) {
280: break;
281: }
282: content.copy(out, NodeInfo.NO_NAMESPACES, false,
283: locationId);
284: }
285: write(out, ">");
286:
287: } else if (localname.equals("notation")) {
288: String notname = Navigator.getAttributeValue(child, "",
289: "name");
290: String nsystem = Navigator.getAttributeValue(child, "",
291: "system");
292: String npublicid = Navigator.getAttributeValue(child,
293: "", "public");
294: if (notname == null) {
295: DynamicError e = new DynamicError(
296: "dtd:notation must have a name attribute");
297: e.setXPathContext(context);
298: throw e;
299: }
300: if ((nsystem == null) && (npublicid == null)) {
301: DynamicError e = new DynamicError(
302: "dtd:notation must have a system attribute or a public attribute");
303: e.setXPathContext(context);
304: throw e;
305: }
306: write(out, "\n <!NOTATION " + notname);
307: if (npublicid != null) {
308: write(out, " PUBLIC \"" + npublicid + "\" ");
309: if (nsystem != null) {
310: write(out, '\"' + nsystem + "\" ");
311: }
312: } else {
313: write(out, " SYSTEM \"" + nsystem + "\" ");
314: }
315: write(out, ">");
316: } else {
317: DynamicError e = new DynamicError(
318: "Unrecognized element " + localname
319: + " in DTD output");
320: e.setXPathContext(context);
321: throw e;
322: }
323: child = (NodeInfo) children.next();
324: }
325:
326: if (openSquare) {
327: write(out, "\n]");
328: }
329: write(out, ">\n");
330:
331: return null;
332:
333: }
334:
335: private void write(Receiver out, String s) throws XPathException {
336: out.characters(s, locationId, ReceiverOptions.DISABLE_ESCAPING);
337: }
338:
339: /**
340: * Diagnostic print of expression structure. The expression is written to the System.err
341: * output stream
342: *
343: * @param level indentation level for this expression
344: * @param out
345: */
346:
347: public void display(int level, NamePool pool, PrintStream out) {
348: out.println(ExpressionTool.indent(level) + "saxon:doctype");
349: }
350: }
351:
352: //
353: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
354: // you may not use this file except in compliance with the License. You may obtain a copy of the
355: // License at http://www.mozilla.org/MPL/
356: //
357: // Software distributed under the License is distributed on an "AS IS" basis,
358: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
359: // See the License for the specific language governing rights and limitations under the License.
360: //
361: // The Original Code is: all this file.
362: //
363: // The Initial Developer of the Original Code is Michael H. Kay.
364: //
365: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
366: //
367: // Contributor(s): none.
368: //
|