001: // Copyright (c) 2002, 2003 Per M.A. Bothner.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.kawa.xslt;
005:
006: import gnu.mapping.*;
007: import gnu.lists.*;
008: import gnu.expr.*;
009: import gnu.text.*;
010: import gnu.xquery.lang.*;
011: import gnu.kawa.xml.*;
012:
013: /** New Kawa language XSLT (XML Stylesheet Language Tranformations). */
014:
015: public class XSLT extends XQuery {
016: // This field need to be public so that the findLiteral method in
017: // gnu.expr.LitTable can find it.
018: public static XSLT instance;
019:
020: public String getName() {
021: return "XSLT";
022: }
023:
024: public XSLT() {
025: instance = this ;
026: ModuleBody.setMainPrintValues(true);
027: }
028:
029: public static XSLT getXsltInstance() {
030: if (instance == null)
031: new XSLT();
032: return instance;
033: }
034:
035: Expression parseXPath(String string, SourceMessages messages) {
036: try {
037: Compilation tr = new Compilation(this , messages);
038: XQParser parser = (XQParser) super .getLexer(
039: new CharArrayInPort(string), messages);
040: //parser.nesting = 1;
041: java.util.Vector exps = new java.util.Vector(20);
042: for (;;) {
043: Expression sexp = parser.parse(tr);
044: if (sexp == null)
045: break;
046: exps.addElement(sexp);
047: }
048: int nexps = exps.size();
049: if (nexps == 0)
050: return QuoteExp.voidExp;
051: else if (nexps == 1)
052: return (Expression) exps.elementAt(0);
053: else
054: throw new InternalError("too many xpath expressions"); // FIXME
055: } catch (Throwable ex) {
056: ex.printStackTrace();
057: throw new InternalError("caught " + ex);
058: }
059: }
060:
061: public gnu.text.Lexer getLexer(InPort inp,
062: gnu.text.SourceMessages messages) {
063: return new XslTranslator(inp, messages, this );
064: }
065:
066: /** Override {@code XQuery} implementation to get {@code Language} default.
067: */
068: public Compilation getCompilation(Lexer lexer,
069: SourceMessages messages) {
070: return new Compilation(this , messages);
071: }
072:
073: public boolean parse(Compilation comp, int options)
074: throws java.io.IOException, gnu.text.SyntaxException {
075: Compilation.defaultCallConvention = Compilation.CALL_WITH_CONSUMER;
076: ((XslTranslator) comp.lexer).parse(comp);
077: return true;
078: }
079:
080: /** The compiler insert calls to this method for applications and applets. */
081: public static void registerEnvironment() {
082: Language.setDefaults(new XSLT());
083: }
084:
085: public static void defineCallTemplate(Symbol name, double priority,
086: Procedure template) {
087: }
088:
089: public static Symbol nullMode = Symbol.make(null, "");
090:
091: public static void defineApplyTemplate(String pattern,
092: double priority, Symbol mode, Procedure template) {
093: if (mode == null)
094: mode = nullMode;
095: TemplateTable table = TemplateTable.getTemplateTable(mode);
096: table.enter(pattern, priority, template);
097: }
098:
099: public static void defineTemplate(Symbol name, String pattern,
100: double priority, Symbol mode, Procedure template) {
101: if (name != null)
102: defineCallTemplate(name, priority, template);
103: if (pattern != null)
104: defineApplyTemplate(pattern, priority, mode, template);
105: }
106:
107: public static void process(TreeList doc, Focus pos, CallContext ctx)
108: throws Throwable {
109: Consumer out = ctx.consumer;
110: for (;;) {
111: int ipos = pos.ipos;
112: int kind = doc.getNextKind(ipos);
113: switch (kind) {
114: case Sequence.DOCUMENT_VALUE:
115: ipos = doc.firstChildPos(ipos);
116: break;
117: case Sequence.ELEMENT_VALUE:
118: Object type = pos.getNextTypeObject();
119: Procedure proc = TemplateTable.nullModeTable.find(pos
120: .getNextTypeName());
121: String name = pos.getNextTypeName();
122: if (proc != null) {
123: proc.check0(ctx);
124: ctx.runUntilDone();
125: } else {
126: out.startElement(type);
127: // FIXME emit attributes
128: pos.push(doc, doc.firstChildPos(ipos));
129: process(doc, pos, ctx);
130: pos.pop();
131: out.endElement();
132: }
133: ipos = doc.nextDataIndex(ipos >>> 1) << 1;
134: pos.gotoNext();
135: break;
136: case Sequence.CHAR_VALUE:
137: int ichild = ipos >>> 1;
138: int next = doc.nextNodeIndex(ichild, -1 >>> 1);
139: if (ipos == next)
140: next = doc.nextDataIndex(ichild);
141: doc.consumeIRange(ichild, next, out);
142: ipos = next << 1;
143: break;
144: case Sequence.TEXT_BYTE_VALUE:
145: case Sequence.OBJECT_VALUE:
146: default:
147: return;
148: }
149: pos.ipos = ipos;
150: }
151: }
152:
153: public static void runStylesheet() throws Throwable {
154: CallContext ctx = CallContext.getInstance();
155: String[] args = kawa.repl.commandLineArgArray;
156: for (int i = 0; i < args.length; i++) {
157: String arg = args[i];
158: KDocument doc = Document.parse(arg);
159: Focus pos = Focus.getCurrent();
160: pos.push(doc.sequence, doc.ipos);
161: process((TreeList) doc.sequence, pos, ctx);
162: }
163: }
164:
165: public static void applyTemplates(String select, Symbol mode)
166: throws Throwable {
167: if (mode == null)
168: mode = nullMode;
169: TemplateTable table = TemplateTable.getTemplateTable(mode);
170: CallContext ctx = CallContext.getInstance();
171: Focus pos = Focus.getCurrent();
172: TreeList doc = (TreeList) pos.sequence;
173: pos.push(doc, doc.firstChildPos(pos.ipos));
174: process(doc, pos, ctx);
175: pos.pop();
176: }
177: }
|