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