001: /*
002: * Copyright 2002-2008 Andy Clark
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package sample;
018:
019: import java.io.BufferedReader;
020: import java.io.IOException;
021: import java.io.PrintWriter;
022: import java.io.StringReader;
023: import java.io.StringWriter;
024:
025: import org.apache.xerces.xni.Augmentations;
026: import org.apache.xerces.xni.QName;
027: import org.apache.xerces.xni.XMLAttributes;
028: import org.apache.xerces.xni.XMLLocator;
029: import org.apache.xerces.xni.XMLString;
030: import org.apache.xerces.xni.XNIException;
031: import org.apache.xerces.xni.parser.XMLDocumentFilter;
032: import org.apache.xerces.xni.parser.XMLInputSource;
033: import org.cyberneko.html.HTMLConfiguration;
034: import org.cyberneko.html.filters.DefaultFilter;
035: import org.cyberneko.html.filters.Identity;
036: import org.cyberneko.html.filters.Writer;
037:
038: /**
039: * This sample demonstrates how to use of the <code>pushInputSource</code>
040: * method of the HTMLConfiguration in order to dynamically insert content
041: * into the HTML stream. The typical use for this functionality is to
042: * insert the result of an embedded script into the HTML document in place
043: * of the script.
044: * <p>
045: * This particular example defines a new script language called "NekoHTML"
046: * script that is a tiny subset of the NSGMLS format. The following table
047: * enumerates the NSGMLS features supported by this script language:
048: * <table border='1' cellspacing='0', cellpadding='3'>
049: * <tr><th>(<i>name</i><td>A start element with the specified <i>name</i>.
050: * <tr><th>"<i>text</i><td>Character content with the specified <i>text</i>.
051: * <tr><th>)<i>name</i><td>An end element with the specified <i>name</i>.
052: * </table>
053: * <p>
054: * In this format, every <i>command</i> is specified on a line by itself.
055: * For example, the following document:
056: * <pre>
057: * <script type='NekoHTML'>
058: * (h1
059: * "Header
060: * )h1
061: * </script>
062: * </pre>
063: * is equivalent to the following HTML document:
064: * <pre>
065: * <H1>Header</H1>
066: * </pre>
067: * as seen by document handler registered with the parser, when processed
068: * by this filter.
069: *
070: * @author Andy Clark
071: *
072: * @version $Id: Script.java,v 1.3 2004/02/19 20:00:17 andyc Exp $
073: */
074: public class Script extends DefaultFilter {
075:
076: //
077: // Constants
078: //
079:
080: /** Augmentations feature identifier. */
081: protected static final String AUGMENTATIONS = "http://cyberneko.org/html/features/augmentations";
082:
083: /** Filters property identifier. */
084: protected static final String FILTERS = "http://cyberneko.org/html/properties/filters";
085:
086: /** Script type ("text/x-nekoscript"). */
087: protected static final String SCRIPT_TYPE = "text/x-nekoscript";
088:
089: //
090: // Data
091: //
092:
093: /** The NekoHTML configuration. */
094: protected HTMLConfiguration fConfiguration;
095:
096: /** A string buffer to collect the "script". */
097: protected StringBuffer fBuffer;
098:
099: /** The system identifier of the source document. */
100: protected String fSystemId;
101:
102: /** The script count. */
103: protected int fScriptCount;
104:
105: //
106: // Constructors
107: //
108:
109: /** Constructs a script object with the specified configuration. */
110: public Script(HTMLConfiguration config) {
111: fConfiguration = config;
112: } // <init>(HTMLConfiguration)
113:
114: //
115: // XMLDocumentHandler methods
116: //
117:
118: /** Start document. */
119: public void startDocument(XMLLocator locator, String encoding,
120: Augmentations augs) throws XNIException {
121: fBuffer = null;
122: fSystemId = locator != null ? locator.getLiteralSystemId()
123: : null;
124: fScriptCount = 0;
125: super .startDocument(locator, encoding, augs);
126: } // startDocument(XMLLocator,String,Augmentations)
127:
128: /** Start element. */
129: public void startElement(QName element, XMLAttributes attrs,
130: Augmentations augs) throws XNIException {
131: if (element.rawname.equalsIgnoreCase("script") && attrs != null) {
132: String value = attrs.getValue("type");
133: if (value != null && value.equalsIgnoreCase(SCRIPT_TYPE)) {
134: fBuffer = new StringBuffer();
135: return;
136: }
137: }
138: super .startElement(element, attrs, augs);
139: } // startElement(QName,XMLAttributes,Augmentations)
140:
141: /** Empty element. */
142: public void emptyElement(QName element, XMLAttributes attrs,
143: Augmentations augs) throws XNIException {
144: if (element.rawname.equalsIgnoreCase("script") && attrs != null) {
145: String value = attrs.getValue("type");
146: if (value != null && value.equalsIgnoreCase(SCRIPT_TYPE)) {
147: return;
148: }
149: }
150: super .emptyElement(element, attrs, augs);
151: } // emptyElement(QName,XMLAttributes,Augmentations)
152:
153: /** Characters. */
154: public void characters(XMLString text, Augmentations augs)
155: throws XNIException {
156: if (fBuffer != null) {
157: fBuffer.append(text.ch, text.offset, text.length);
158: } else {
159: super .characters(text, augs);
160: }
161: } // characters(XMLString,Augmentations)
162:
163: /** End element. */
164: public void endElement(QName element, Augmentations augs)
165: throws XNIException {
166: if (fBuffer != null) {
167: try {
168: // run "script" and generate HTML output
169: BufferedReader in = new BufferedReader(
170: new StringReader(fBuffer.toString()));
171: StringWriter sout = new StringWriter();
172: PrintWriter out = new PrintWriter(sout);
173: String line;
174: while ((line = in.readLine()) != null) {
175: line.trim();
176: if (line.length() == 0) {
177: continue;
178: }
179: switch (line.charAt(0)) {
180: case '(': {
181: out.print('<');
182: out.print(line.substring(1));
183: out.print('>');
184: break;
185: }
186: case '"': {
187: out.print(line.substring(1));
188: break;
189: }
190: case ')': {
191: out.print("</");
192: out.print(line.substring(1));
193: out.print('>');
194: break;
195: }
196: }
197: }
198:
199: // push new input source
200: String systemId = fSystemId != null ? fSystemId + '_'
201: : "";
202: fScriptCount++;
203: systemId += "script" + fScriptCount;
204: XMLInputSource source = new XMLInputSource(null,
205: systemId, null, new StringReader(sout
206: .toString()), "UTF-8");
207: fConfiguration.pushInputSource(source);
208: } catch (IOException e) {
209: // ignore
210: } finally {
211: fBuffer = null;
212: }
213: } else {
214: super .endElement(element, augs);
215: }
216: } // endElement(QName,Augmentations)
217:
218: //
219: // MAIN
220: //
221:
222: /** Main. */
223: public static void main(String[] argv) throws Exception {
224: HTMLConfiguration parser = new HTMLConfiguration();
225: parser.setFeature(AUGMENTATIONS, true);
226: XMLDocumentFilter[] filters = { new Script(parser),
227: new Identity(), new Writer() };
228: parser.setProperty(FILTERS, filters);
229: for (int i = 0; i < argv.length; i++) {
230: parser.parse(new XMLInputSource(null, argv[i], null));
231: }
232: } // main(String[])
233:
234: } // class Script
|