first alpha release
[org.ibex.xt.git] / src / org / ibex / xt / Node.java
diff --git a/src/org/ibex/xt/Node.java b/src/org/ibex/xt/Node.java
new file mode 100644 (file)
index 0000000..f4fe0a4
--- /dev/null
@@ -0,0 +1,166 @@
+package org.ibex.xt;
+import org.ibex.js.*;
+import org.ibex.util.*;
+import org.ibex.io.*;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+public class Node {
+
+    public String   name = null;
+    public String   cdata = null;
+    public int      numattrs = 0;
+    public String[] attrs = null;
+    public String   uri = null;
+    private int     delta = 0;
+
+    public Node() { }
+    public Node(Node n) { copyFrom(n); }
+    public final void clear() { name = null; cdata = null; numattrs = 0; delta = 0; uri = null; }
+    public final void copyFrom(Node n) {
+        name=n.name; cdata=n.cdata; numattrs=n.numattrs; delta=n.delta; uri=n.uri;
+        if (n.attrs == null) { attrs = null; return; }
+        attrs = new String[n.attrs.length]; System.arraycopy(n.attrs, 0, attrs, 0, attrs.length); }
+    public final String attr(String key) {
+        for(int i=0; i<numattrs; i++) if (key.equals(attrs[i*2])) return attrs[i*2+1]; return null; }
+
+    public static abstract class Stream {
+        public static final Stream NULL = new Stream() { public boolean _read(Node n) { return false; } };
+        public static interface Functor { public Node.Stream wrap(Node.Stream in); }
+        public static class ConstantFunctor implements Functor {
+            private final Node.Stream stream;
+            public ConstantFunctor(Node.Stream stream) { this.stream = stream; }
+            public Node.Stream wrap(Node.Stream in) { return stream; }
+        }
+        public static abstract class Filter extends Stream {
+            Stream upstream;
+            Filter() { }
+            public Filter(Stream upstream) { this.upstream = upstream; }
+            public boolean upstreamRead(Node n) { upstream = upstream.simplify(); return upstream.read(n); }
+            public void wrapUpstream(Functor f) { upstream = f.wrap(upstream); }
+            public Filter graft(Functor f, Node n) {
+                upstream = new Graft((upstream instanceof Peekable) ? (Peekable)upstream : new Peekable(upstream), n, f);
+                return this;
+            }
+        }
+
+        public Stream simplify() { return this; }
+        protected abstract boolean _read(Node n);
+        public final boolean read(Node n) { n.clear(); if (!_read(n)) { n.clear(); return false; } return true; }
+
+        public static class Peekable extends Filter {
+            public Peekable(Stream s) { super(s); }
+            private Node pending = null;
+            public boolean peek(Node n) {
+                if (pending == null) {
+                    Node n2 = new Node();
+                    if (!upstreamRead(n2)) return false;
+                    pending = n2;
+                }
+                n.copyFrom(pending);
+                return true;
+            }
+            public boolean _read(Node n) {
+                if (pending != null) { n.copyFrom(pending); pending = null; return true; }
+                return upstreamRead(n);
+            }
+        }
+
+        private static class Graft extends Filter {
+            private Stream inner2;
+            private Peekable a;
+            int total = 0;
+            int net = 0;
+            boolean simple = false;
+            private Node pending = new Node();
+            public Graft(final Peekable a, final Node n, final Functor f) {
+                this.a = a;
+                upstream = inner2 = new Stream() {
+                        public boolean _read(Node n) {
+                            if (!Graft.this.a.peek(n)) return false;
+                            if (net + n.delta <= 0) return false;
+                            Graft.this.a.read(n);
+                            net += n.delta;
+                            return true;
+                        } };
+                wrapUpstream(f);
+                if (__read(pending)) pending.delta = n.delta;
+                total = n.delta;
+            }
+            public boolean _read(Node n) {
+                if (pending != null) { n.copyFrom(pending); pending = null; return true; }
+                boolean ret = __read(n);
+                if (ret) total += n.delta;
+                return ret;
+            }
+            public boolean __read(Node n) {
+                if (simple) return a.read(n);
+                if (upstreamRead(n)) return true;
+                while(inner2.read(n));
+                if (!a.read(n)) return false;
+                n.delta += net - total;
+                simple = true;
+                return true;
+            }
+        }
+
+        public static class FromXML extends Node.Stream {
+            private final XML.Pull xml;
+            private XML.Element parent = null;
+            private XML.Element e;
+            private int currentdelta = 0;
+            public FromXML(Reader r) { this.xml = new XML.Pull(r); }
+            protected boolean _read(Node n) { try {
+                Object ret = xml.read();
+                if (ret == null) return false;
+                if (ret instanceof String) {
+                    n.cdata = (String)ret;
+                    n.delta = xml.level - currentdelta;
+                    currentdelta = xml.level;
+                    return true;
+                }
+                XML.Element e = (XML.Element)ret;
+                n.name = e.getLocalName();
+                n.uri = e.getUri();
+                n.numattrs = e.getAttrLen();
+                n.delta = e.level - currentdelta;
+                currentdelta = e.level;
+                if (n.attrs == null || n.attrs.length < n.numattrs*2) n.attrs = new String[n.numattrs*4];
+                for(int i=0; i<n.numattrs; i++) { n.attrs[i*2]   = e.getAttrKey(i); n.attrs[i*2+1] = e.getAttrVal(i); }
+                return true;
+            } catch (Exception e) { throw new RuntimeException(e); } }
+        }
+
+        public void toXML(Writer writer) throws IOException { Node n = new Node(); if (read(n)) toXML(writer, n); }
+        private Node toXML(Writer w, Node n) throws IOException {
+            final String name = n.name;
+            if (n.cdata != null) {
+                w.write(n.cdata);
+                if (!read(n)) n = null;
+            } else {
+                w.write("<");
+                w.write(name);
+                for(int i=0; i < n.numattrs * 2; i+=2) {
+                    w.write(" ");
+                    w.write(n.attrs[i]);
+                    w.write("=\"");
+                    w.write(n.attrs[i+1]);
+                    w.write("\"");
+                }
+                if (!read(n)) n = null;
+                if (n == null || n.delta <= 0) {
+                    w.write("/>");
+                } else {
+                    w.write(">");
+                    while(n != null && n.delta > 0) n = toXML(w, n);
+                    w.write("</");
+                    w.write(name);
+                    w.write(">");
+                }
+            }
+            if (n != null) n.delta++;
+            return n;
+        }
+    }
+}