finished updating xt for new JS API
[org.ibex.xt.git] / src / org / ibex / xt / Node.java
1 // Copyright 2000-2005 the Contributors, as shown in the revision logs.
2 // Licensed under the Apache Public Source License 2.0 ("the License").
3 // You may not use this file except in compliance with the License.
4
5 package org.ibex.xt;
6 import org.ibex.js.*;
7 import org.ibex.util.*;
8 import org.ibex.io.*;
9 import java.io.*;
10 import java.net.*;
11 import java.util.*;
12
13 public class Node {
14
15     public String   name = null;
16     public String   cdata = null;
17     public int      numattrs = 0;
18     public String[] attrs = null;
19     public String   uri = null;
20     private int     delta = 0;
21
22     public Node() { }
23     public Node(Node n) { copyFrom(n); }
24     public final void clear() { name = null; cdata = null; numattrs = 0; delta = 0; uri = null; }
25     public final void copyFrom(Node n) {
26         name=n.name; cdata=n.cdata; numattrs=n.numattrs; delta=n.delta; uri=n.uri;
27         if (n.attrs == null) { attrs = null; return; }
28         attrs = new String[n.attrs.length]; System.arraycopy(n.attrs, 0, attrs, 0, attrs.length); }
29     public final String attr(String key) {
30         for(int i=0; i<numattrs; i++) if (key.equals(attrs[i*2])) return attrs[i*2+1]; return null; }
31
32     public static abstract class Stream {
33         public static final Stream NULL = new Stream() { public boolean _read(Node n) { return false; } };
34         public static interface Functor { public Node.Stream wrap(Node.Stream in); }
35         public static class ConstantFunctor implements Functor {
36             private final Node.Stream stream;
37             public ConstantFunctor(Node.Stream stream) { this.stream = stream; }
38             public Node.Stream wrap(Node.Stream in) { return stream; }
39         }
40         public static abstract class Filter extends Stream {
41             Stream upstream;
42             Filter() { }
43             public Filter(Stream upstream) { this.upstream = upstream; }
44             public boolean upstreamRead(Node n) { upstream = upstream.simplify(); return upstream.read(n); }
45             public void wrapUpstream(Functor f) { upstream = f.wrap(upstream); }
46             public Filter graft(Functor f, Node n) {
47                 upstream = new Graft((upstream instanceof Peekable) ? (Peekable)upstream : new Peekable(upstream), n, f);
48                 return this;
49             }
50         }
51
52         public Stream simplify() { return this; }
53         protected abstract boolean _read(Node n);
54         public final boolean read(Node n) { n.clear(); if (!_read(n)) { n.clear(); return false; } return true; }
55
56         public static class Peekable extends Filter {
57             public Peekable(Stream s) { super(s); }
58             private Node pending = null;
59             public boolean peek(Node n) {
60                 if (pending == null) {
61                     Node n2 = new Node();
62                     if (!upstreamRead(n2)) return false;
63                     pending = n2;
64                 }
65                 n.copyFrom(pending);
66                 return true;
67             }
68             public boolean _read(Node n) {
69                 if (pending != null) { n.copyFrom(pending); pending = null; return true; }
70                 return upstreamRead(n);
71             }
72         }
73
74         private static class Graft extends Filter {
75             private Stream inner2;
76             private Peekable a;
77             int total = 0;
78             int net = 0;
79             boolean simple = false;
80             private Node pending = new Node();
81             public Graft(final Peekable a, final Node n, final Functor f) {
82                 this.a = a;
83                 upstream = inner2 = new Stream() {
84                         public boolean _read(Node n) {
85                             if (!Graft.this.a.peek(n)) return false;
86                             if (net + n.delta <= 0) return false;
87                             Graft.this.a.read(n);
88                             net += n.delta;
89                             return true;
90                         } };
91                 wrapUpstream(f);
92                 if (__read(pending)) pending.delta = n.delta;
93                 total = n.delta;
94             }
95             public boolean _read(Node n) {
96                 if (pending != null) { n.copyFrom(pending); pending = null; return true; }
97                 boolean ret = __read(n);
98                 if (ret) total += n.delta;
99                 return ret;
100             }
101             public boolean __read(Node n) {
102                 if (simple) return a.read(n);
103                 if (upstreamRead(n)) return true;
104                 while(inner2.read(n));
105                 if (!a.read(n)) return false;
106                 n.delta += net - total;
107                 simple = true;
108                 return true;
109             }
110         }
111
112         public static class FromXML extends Node.Stream {
113             private final XML.Stream xml;
114             private XML.Elem parent = null;
115             private XML.Elem e;
116             private int currentdelta = 0;
117             public FromXML(Reader r) { this.xml = new XML.Stream(r); }
118             protected boolean _read(Node n) { try {
119                 Object ret = xml.next();
120                 if (ret == null) return false;
121                 if (ret instanceof XML.Text) {
122                     n.cdata = ((XML.Text)ret).t;
123                     n.delta = xml.getDepth() - currentdelta;
124                     currentdelta = xml.getDepth();
125                     return true;
126                 }
127                 XML.Elem e = (XML.Elem)ret;
128                 n.name = e.getLocalName();
129                 n.uri = e.getUri();
130                 n.numattrs = e.getAttributes().attrSize();
131                 n.delta = xml.getDepth() - currentdelta;
132                 currentdelta = xml.getDepth();
133                 if (n.attrs == null || n.attrs.length < n.numattrs*2) n.attrs = new String[n.numattrs*4];
134                 for(int i=0; i<n.numattrs; i++) {
135                     n.attrs[i*2] = e.getAttributes().getKey(i);
136                     n.attrs[i*2+1] = e.getAttributes().getVal(i);
137                 }
138                 return true;
139             } catch (Exception e) { throw new RuntimeException(e); } }
140         }
141
142         public void toXML(Writer writer) throws IOException {
143             Node n = new Node();
144             do { if (!read(n)) n = null; } while (n!=null && n.cdata != null);
145             toXML(writer, n);
146         }
147         private Node toXML(Writer w, Node n) throws IOException {
148             final String name = n.name;
149             if (n.cdata != null) {
150                 w.write(n.cdata);
151                 if (!read(n)) n = null;
152             } else {
153                 w.write("<");
154                 w.write(name);
155                 for(int i=0; i < n.numattrs * 2; i+=2) {
156                     w.write(" ");
157                     w.write(n.attrs[i]);
158                     w.write("=\"");
159                     w.write(n.attrs[i+1]);
160                     w.write("\"");
161                 }
162                 if (!read(n)) n = null;
163                 if (n == null || n.delta <= 0) {
164                     w.write("/>");
165                 } else {
166                     w.write(">");
167                     while(n != null && n.delta > 0) {  n = toXML(w, n); }
168                     w.write("</");
169                     w.write(name);
170                     w.write(">");
171                 }
172             }
173             if (n != null) n.delta++;
174             return n;
175         }
176     }
177 }