[gxml] XParser: Initial for read/write
- From: Daniel Espinosa Ortiz <despinosa src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gxml] XParser: Initial for read/write
- Date: Mon, 31 Oct 2016 04:13:11 +0000 (UTC)
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]