[gxml] XParser: Initial for read/write



commit 2d7e981425b42fa2144c5af93ac62583a525edf0
Author: Daniel Espinosa <esodan gmail com>
Date:   Thu Oct 27 19:01:28 2016 -0500

    XParser: Initial for read/write

 gxml/Parser.vala  |   43 ++++++-
 gxml/XParser.vala |  341 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 370 insertions(+), 14 deletions(-)
---
diff --git a/gxml/Parser.vala b/gxml/Parser.vala
index 7f2c894..5e1e1bd 100644
--- a/gxml/Parser.vala
+++ b/gxml/Parser.vala
@@ -25,13 +25,46 @@ using Gee;
  * XML parser engine for {@link DomDocument} implementations.
  */
 public interface GXml.Parser : Object {
+  /**
+   * A {@link GXml.DomDocument} to read to or write from
+   */
   public abstract DomDocument document { get; }
-  public abstract void save (GLib.File f,
+  /**
+   * A {@link GXml.DomNode.NodeType} of the current node read
+   */
+  public abstract DomNode.NodeType current_type { get; }
+  /**
+   * Writes a {@link GXml.DomDocument} to a {@link GLib.File}
+   */
+  public abstract void write (GLib.File f,
                             GLib.Cancellable? cancellable) throws GLib.Error;
+  /**
+   * Writes a {@link GXml.DomDocument} to a string
+   */
+  public abstract string write_string () throws GLib.Error;
+  /**
+   * Writes a {@link GXml.DomDocument} to a {@link GLib.OutputStream}
+   */
+  public abstract void write_stream (OutputStream stream
+                                    GLib.Cancellable? cancellable) throws GLib.Error;
+
+  /**
+   * Read a {@link GXml.DomDocument} from a {@link GLib.File}
+   */
   public abstract void read (GLib.File f,
                             GLib.Cancellable? cancellable) throws GLib.Error;
-  public abstract string to_string () throws GLib.Error;
-  public abstract void to_stream (OutputStream stream) throws GLib.Error;
-  public abstract void from_stream (InputStream stream) throws GLib.Error;
-  public abstract void from_string (string str);
+  /**
+   * Read a {@link GXml.DomDocument} from a {@link GLib.InputStream}
+   */
+  public abstract void read_stream (InputStream stream
+                                   GLib.Cancellable? cancellable) throws GLib.Error;
+  /**
+   * Read a {@link GXml.DomDocument} from a {@link GLib.File}
+   */
+  public abstract void read_string (string str);
+  /**
+   * From data stream read until a node is found. You should check its type
+   * using {@link current_type}
+   */
+  public abstract bool read_node ();
 }
diff --git a/gxml/XParser.vala b/gxml/XParser.vala
index 373e3cd..17bbee1 100644
--- a/gxml/XParser.vala
+++ b/gxml/XParser.vala
@@ -25,17 +25,340 @@ using Gee;
  * {@link Parser} implementation using libxml2 engine
  */
 public class GXml.XParser : Object, GXml.Parser {
-  DomDocument _document;
+  private DomDocument _document;
+  private TextReader tr;
+
   public DomDocument document { get { return _document; } }
 
+  public bool indent { get; set; }
+
   public XParser (DomDocument doc) { _document = doc; }
 
-  public void save (GLib.File f, GLib.Cancellable? cancellable)
-   throws GLib.Error {}
-  public void read (GLib.File f, GLib.Cancellable? cancellable)
-  throws GLib.Error {}
-  public string to_string () throws GLib.Error  { return ""; }
-  public void to_stream (OutputStream stream) throws GLib.Error {}
-  public void from_stream (InputStream stream) throws GLib.Error {}
-  public void from_string (string str) {}
+  public void write (GLib.File f, GLib.Cancellable? cancellable) throws GLib.Error {}
+  public string write_string () throws GLib.Error  { return ""; }
+  public void write_stream (OutputStream stream) throws GLib.Error {}
+  public void read_string (string str) {
+    try {
+#if DEBUG
+    GLib.message ("TDocument: to_string ()");
+#endif
+    Xml.Doc doc = new Xml.Doc ();
+    Xml.TextWriter tw = Xmlx.new_text_writer_doc (ref doc);
+    write_document (this, tw);
+    string str;
+    int size;
+    doc.dump_memory (out str, out size);
+    return str;
+    } catch (GLib.Error e) { return "ERROR: "+e.message; }
+  }
+
+
+  public void read (GLib.File file,  GLib.Cancellable? cancellable) throws GLib.Error {
+    if (!file.query_exists ())
+      throw new GXml.DocumentError.INVALID_FILE (_("File doesn't exist"));
+    read_stream (file.read (), cancellable);
+  }
+
+  public void read_stream (GLib.InputStream istream,
+                          GLib.Cancellable? cancellable) throws GLib.Error {
+    var b = new MemoryOutputStream.resizable ();
+    b.splice (istream, 0);
+#if DEBUG
+    GLib.message ("FILE:"+(string)b.data);
+#endif
+    var tr = new TextReader.for_memory ((char[]) b.data, (int) b.get_data_size (), "/gxml_memory");
+    _current = _document;
+    while (read_node ());
+  }
+
+
+  /**
+   * Parse current node in {@link Xml.TextReader}.
+   *
+   * Returns: a {@link GXml.Node} respresenting current parsed one.
+   */
+  public bool read_node (DomNode node) throws GLib.Error {
+    GXml.DomNode n = null;
+    string prefix, nsuri;
+    if (tr.read () != 1) return false;
+    if (tr.next () != 1) return false;
+    var t = tr.node_type (); // FIXME: Convert to NodeType and store
+#if DEBUG
+    GLib.message ("ReadNode: Current Node:"+node.node_name);
+#endif
+    switch (t) {
+    case Xml.ReaderType.NONE:
+#if DEBUG
+      GLib.message ("Type NONE");
+#endif
+      if (tr.read () != 1) return false;
+      break;
+    case Xml.ReaderType.ELEMENT:
+      bool isempty = (tr.is_empty_element () == 1);
+#if DEBUG
+      if (isempty) GLib.message ("Is Empty node:"+node.name);
+      GLib.message ("ReadNode: Element: "+tr.const_local_name ());
+#endif
+      if (isempty) {
+        return true;;
+      }
+      var cont = true;
+      while (cont) {
+        if (tr.read () != 1) return false;
+        t = tr.node_type ();
+        if (t == Xml.ReaderType.END_ELEMENT) {
+          if (tr.const_local_name () == n.node_name) {
+            cont = false;
+          }
+        }
+      }
+      return true;
+#if DEBUG
+      //GLib.message ("ReadNode: next node:"+n.to_string ());
+      //GLib.message ("ReadNode: next node attributes:"+(tr.has_attributes ()).to_string ());
+#endif
+      prefix = tr.prefix ();
+      if (prefix != null) {
+        nsuri = tr.lookup_namespace (prefix);
+        n = _document.create_element_ns (nsuri, tr.prefix + tr.const_local_name ());
+      } else
+        n = _document.create_element (tr.const_local_name ());
+      node.append_child (n);
+      var nattr = tr.attribute_count ();
+#if DEBUG
+      GLib.message ("Number of Attributes:"+nattr.to_string ());
+#endif
+      for (int i = 0; i < nattr; i++) {
+        var c = tr.move_to_attribute_no (i);
+#if DEBUG
+        GLib.message ("Current Attribute: "+i.to_string ());
+#endif
+        if (c != 1) {
+          throw new DomError.HIERARCHY_REQUEST_ERROR (_("Parsing ERROR: Fail to move to attribute number: 
%i").printf (i));
+        }
+        if (tr.is_namespace_decl () == 1) {
+#if DEBUG
+          GLib.message ("Is Namespace Declaration...");
+#endif
+          string nsp = tr.const_local_name ();
+          prefix = tr.prefix ();
+          tr.read_attribute_value ();
+          if (tr.node_type () == Xml.ReaderType.TEXT) {
+            nsuri = tr.read_string ();
+            (n as DomElement).set_attribute_ns (nsuri, prefix+":"+nsp, nsuri);
+          }
+        } else {
+          var attrname = tr.const_local_name ();
+          prefix = tr.prefix ();
+#if DEBUG
+          GLib.message ("Attribute: "+tr.const_local_name ());
+#endif
+          tr.read_attribute_value ();
+          if (tr.node_type () == Xml.ReaderType.TEXT) {
+            var attrval = tr.read_string ();
+#if DEBUG
+            GLib.message ("Attribute:"+attrname+" Value: "+attrval);
+#endif
+            if (prefix != null) {
+              nsuri = tr.lookup_namespace (prefix);
+              (n as DomElement).set_attribute_ns (nsuri, prefix+":"+attrname, attrval);
+            } else
+              (n as DomElement).set_attribute (attrname, attrval);
+          }
+        }
+      }
+      if (isempty) return true;
+      while (read_node (n) == true);
+#if DEBUG
+      //GLib.message ("Current Document: "+node.document.to_string ());
+#endif
+      break;
+    case Xml.ReaderType.ATTRIBUTE:
+#if DEBUG
+      GLib.message ("Type ATTRIBUTE");
+#endif
+      break;
+    case Xml.ReaderType.TEXT:
+      var txtval = tr.read_string ();
+#if DEBUG
+      GLib.message ("Type TEXT");
+      GLib.message ("ReadNode: Text Node : '"+txtval+"'");
+#endif
+      n = _document.create_text_node (txtval);
+      node.append_child (n);
+      break;
+    case Xml.ReaderType.CDATA:
+      break;
+    case Xml.ReaderType.ENTITY_REFERENCE:
+#if DEBUG
+      GLib.message ("Type ENTITY_REFERENCE");
+#endif
+      break;
+    case Xml.ReaderType.ENTITY:
+#if DEBUG
+      GLib.message ("Type ENTITY");
+#endif
+      break;
+    case Xml.ReaderType.PROCESSING_INSTRUCTION:
+      var pit = tr.const_local_name ();
+      var pival = tr.value ();
+#if DEBUG
+      GLib.message ("Type PROCESSING_INSTRUCTION");
+      GLib.message ("ReadNode: PI Node : '"+pit+"' : '"+pival+"'");
+#endif
+      n = node.document.create_processing_instruction (pit,pival);
+      node.append_child (n);
+      break;
+    case Xml.ReaderType.COMMENT:
+      var commval = tr.value ();
+#if DEBUG
+      GLib.message ("Type COMMENT");
+      GLib.message ("ReadNode: Comment Node : '"+commval+"'");
+#endif
+      n = node.document.create_comment (commval);
+      node.append_child (n);
+      break;
+    case Xml.ReaderType.DOCUMENT:
+#if DEBUG
+      GLib.message ("Type DOCUMENT");
+#endif
+      break;
+    case Xml.ReaderType.DOCUMENT_TYPE:
+#if DEBUG
+      GLib.message ("Type DOCUMENT_TYPE");
+#endif
+      break;
+    case Xml.ReaderType.DOCUMENT_FRAGMENT:
+#if DEBUG
+      GLib.message ("Type DOCUMENT_FRAGMENT");
+#endif
+      break;
+    case Xml.ReaderType.NOTATION:
+#if DEBUG
+      GLib.message ("Type NOTATION");
+#endif
+      break;
+    case Xml.ReaderType.WHITESPACE:
+#if DEBUG
+      GLib.message ("Type WHITESPACE");
+#endif
+      break;
+    case Xml.ReaderType.SIGNIFICANT_WHITESPACE:
+#if DEBUG
+      GLib.message ("Type SIGNIFICANT_WHITESPACE");
+#endif
+      break;
+    case Xml.ReaderType.END_ELEMENT:
+#if DEBUG
+      GLib.message ("Type END_ELEMENT");
+#endif
+      return false;
+    case Xml.ReaderType.END_ENTITY:
+#if DEBUG
+      GLib.message ("Type END_ENTITY");
+#endif
+      return false;
+    case Xml.ReaderType.XML_DECLARATION:
+#if DEBUG
+      GLib.message ("Type XML_DECLARATION");
+#endif
+      break;
+    }
+    return true;
+  }
+
+  private string dump_memory (TextWriter tw) {
+    tw.start_document ();
+    tw.set_indent (indent);
+    // Root
+    if (_document.document_element == null) {
+      tw.end_document ();
+    }
+    var dns = new ArrayList<string> ();
+#if DEBUG
+    GLib.message ("Starting writting Document child nodes");
+#endif
+    start_node (tw, _document);
+#if DEBUG
+    GLib.message ("Ending writting Document child nodes");
+#endif
+    tw.end_element ();
+#if DEBUG
+    GLib.message ("Ending Document");
+#endif
+    tw.end_document ();
+    tw.flush ();
+  }
+  private void start_node (Xml.TextWriter tw,
+                          GXml.Node node)
+    throws GLib.Error
+  {
+    int size = 0;
+#if DEBUG
+    GLib.message (@"Starting Node: start Node: '$(node.name)'");
+#endif
+    if (node is GXml.DomElement) {
+#if DEBUG
+      GLib.message (@"Starting Element... '$(node.name)'");
+      GLib.message (@"Element Document is Null... '$((node.document == null).to_string ())'");
+      GLib.message (@"Namespaces in Element... '$(node.namespaces.size)'");
+#endif
+      if ((node as DomElement).prefix != null || (node as DomElement).namespace_uri != null)
+        tw.start_element_ns ((node as DomElement).prefix, node.local_name, (node as DomElement).node_name);
+      else // Don't prefix. Using default namespace and prefix_default_ns = false
+        tw.start_element (node.name);
+    foreach (GXml.DomNode attr in node.attributes.values) {
+#if DEBUG
+        GLib.message (@"Starting Element '$(node.node_name)': write attribute '$(attr.loca_name)'");
+#endif
+      if (attr.prefix != null)
+        size += tw.write_attribute_ns (attr.prefix, attr.local_name, attr.namespace_uri, attr.node_value);
+      else
+        size += tw.write_attribute (attr.name, attr.value);
+      if (size > 1500)
+        tw.flush ();
+    }
+  }
+  // Non Elements
+#if DEBUG
+    GLib.message (@"Starting Element: writting Node '$(node.node_name)' children");
+#endif
+    foreach (GXml.DomNode n in node.child_nodes) {
+#if DEBUG
+      GLib.message (@"Child Node is: $(n.get_type ().name ())");
+#endif
+      if (n is GXml.DomElement) {
+#if DEBUG
+      GLib.message (@"Starting Child Element: writting Node '$(n.name)'");
+#endif
+        start_node (tw, n);
+        size += tw.end_element ();
+        if (size > 1500)
+          tw.flush ();
+      }
+      if (n is GXml.DomText) {
+      //GLib.message ("Writting Element's contents");
+      size += tw.write_string (n.node_value);
+      if (size > 1500)
+        tw.flush ();
+      }
+      if (n is GXml.DomComment) {
+#if DEBUG
+      GLib.message (@"Starting Child Element: writting Comment '$(n.node_value)'");
+#endif
+        size += tw.write_comment (n.node_value);
+        if (size > 1500)
+          tw.flush ();
+      }
+      if (n is GXml.DomProcessingInstruction) {
+  #if DEBUG
+      GLib.message (@"Starting Child Element: writting ProcessingInstruction '$(n.value)'");
+  #endif
+        size += Xmlx.text_writer_write_pi (tw, ((n as DomProcessingInstruction).target,
+                                          (n as DomProcessingInstruction).data);
+        if (size > 1500)
+          tw.flush ();
+      }
+    }
+  }
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]