[gxml] DOM4: Implementing DomElement on GElement



commit 96d5f16cde00610cc1242690c27aec5959761917
Author: Daniel Espinosa <esodan gmail com>
Date:   Wed Jul 13 16:17:14 2016 -0500

    DOM4: Implementing DomElement on GElement
    
    * I've take advantage of Vala's interface implementation of different
      interfaces with same methods' names, making no necesary to break API
    
    This is a work in progress, it doesn't compile at all. Requires to
    implement all interfaces before start to fix compilation.

 gxml/Document.vala           |    4 +-
 gxml/DomCollections.vala     |   31 ++++++-
 gxml/DomElement.vala         |    6 +-
 gxml/DomNode.vala            |  103 +++++++++++---------
 gxml/Element.vala            |    4 +
 gxml/GXmlDocument.vala       |    9 +-
 gxml/GXmlDomCollections.vala |  220 ++++++++++++++++++++++++++++++++++++++++++
 gxml/GXmlElement.vala        |  149 ++++++++++++++++++++++++++++-
 gxml/Makefile.am             |    1 +
 9 files changed, 467 insertions(+), 60 deletions(-)
---
diff --git a/gxml/Document.vala b/gxml/Document.vala
index 3510a33..7fd87ea 100644
--- a/gxml/Document.vala
+++ b/gxml/Document.vala
@@ -76,7 +76,7 @@ public interface GXml.Document : Object, GXml.Node
    * Is a matter of you to add as a child to any other
    * {@link GXml.Node}.
    */
-  public abstract GXml.Node create_element_node (string name) throws GLib.Error;
+  public abstract GXml.Node create_element (string name) throws GLib.Error;
   /**
    * Creates a new {@link GXml.Text}.
    *
@@ -90,7 +90,7 @@ public interface GXml.Document : Object, GXml.Node
    * Is a matter of you to add as a child to any other
    * {@link GXml.Node}, like a {@link GXml.Element} node.
    */
-  public abstract GXml.Node create_comment_node (string text);
+  public abstract GXml.Node create_comment (string text);
   /**
    * Creates a new {@link GXml.CDATA}.
    *
diff --git a/gxml/DomCollections.vala b/gxml/DomCollections.vala
index 8241dc6..b79a084 100644
--- a/gxml/DomCollections.vala
+++ b/gxml/DomCollections.vala
@@ -1,4 +1,4 @@
-/* -*- Mode: vala; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
+/* -*- Mode: vala; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
 /*
  *
  * Copyright (C) 2016  Daniel Espinosa <esodan gmail com>
@@ -105,7 +105,7 @@ public class GXml.DomNodeFilter : Object {
   public const ulong SHOW_DOCUMENT_FRAGMENT = 0x400;
   public const ulong SHOW_NOTATION = 0x800; // historical
 
-  public ushort acceptNode(Node node); // FIXME:
+  public ushort acceptNode(Node node); // FIXME: Should be a User defined method
 }
 
 public interface GXml.DomTreeWalker : Object {
@@ -123,3 +123,30 @@ public interface GXml.DomTreeWalker : Object {
   public abstract DomNode? nextNode();
 }
 
+public interface GXml.DomTokenList : Object, Gee.BidirList<string> {
+  public abstract ulong length { get; }
+  public abstract string? item (ulong index);
+  public abstract bool contains (string token) throw GLib.Error ;
+  public abstract void add (string[] tokens) throw GLib.Error ;
+  public abstract void remove (string[] tokens) throw GLib.Error ;
+  public abstract bool toggle (string token, bool force = false) throws GLib.Error;
+  public abstract string to_string ();
+}
+
+public interface GXml.DomSettableTokenList : Object, DOMTokenList {
+  public abstract string value { get; set; }
+}
+
+public interface GXml.DomNamedNodeMap : Object {
+  public ulong length { get; }
+  public DomNode? item (ulong index);
+  public DomNode? get_named_item (string name);
+  public DomNode? set_named_item (DomNode node) throws GLib.Error;
+  public DomNode? remove_named_item (string name) throws GLib.Error;
+  // Introduced in DOM Level 2:
+  public DomNode? remove_named_item_ns (string namespace_uri, string localName) throws GLib.Error;
+  // Introduced in DOM Level 2:
+  public DomNode? get_named_item_ns (string namespace_uri, string local_name) throws GLib.Error;
+  // Introduced in DOM Level 2:
+  public DomNode? set_named_item_ns (DomNode node) throws GLib.Error;
+}
diff --git a/gxml/DomElement.vala b/gxml/DomElement.vala
index 9c9703a..3b9e556 100644
--- a/gxml/DomElement.vala
+++ b/gxml/DomElement.vala
@@ -1,4 +1,4 @@
-/* -*- Mode: vala; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
+/* -*- Mode: vala; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
 /*
  *
  * Copyright (C) 2016  Daniel Espinosa <esodan gmail com>
@@ -28,7 +28,7 @@ public interface GXml.DomElement : GLib.Object, GXml.DomNode, GXml.DomParentNode
 
   public abstract string id { get; set; }
   public abstract string class_name  { get; set; }
-  public abstract DomTokenList class_list { get; }
+  public abstract DomTokenList class_list { owned get; }
 
   public abstract DomNamedNodeMap attributes { get; }
   public abstract string? get_attribute (string name);
@@ -41,7 +41,7 @@ public interface GXml.DomElement : GLib.Object, GXml.DomNode, GXml.DomParentNode
   public abstract bool has_attribute_ns (string? namespace, string local_name);
 
 
-  public abstract DomHTMLCollection get_elementsby_tag_name(string local_name);
+  public abstract DomHTMLCollection get_elements_by_tag_name(string local_name);
   public abstract DomHTMLCollection get_elements_by_tag_name_ns (string? namespace, string local_name);
   public abstract DomHTMLCollection get_elements_by_class_name (string class_names);
 }
diff --git a/gxml/DomNode.vala b/gxml/DomNode.vala
index 1fb0fcd..2524f0d 100644
--- a/gxml/DomNode.vala
+++ b/gxml/DomNode.vala
@@ -80,59 +80,70 @@ public interface GXml.DomNode : GLib.Object, GXml.DomEventTarget {
   public abstract DomNode remove_child (DomNode child);
 }
 
+// Introduced in DOM Level 3:
+const unsigned short      VALIDATION_ERR                 = 16;
+// Introduced in DOM Level 3:
+const unsigned short      TYPE_MISMATCH_ERR              = 17;
+
 public errordomain GXml.DomError {
-       INDEX_SIZE_ERROR,
-       HIERARCHY_REQUEST_ERROR,
-       WRONG_DOCUMENT_ERROR,
-       INVALID_CHARACTER_ERROR,
-       NO_MODIFICATION_ALLOWED_ERROR,
-       NOT_FOUND_ERROR,
-       NOT_SUPPORTED_ERROR,
-       INVALID_STATE_ERROR,
-       SYNTAX_ERROR,
-       INVALID_MODIFICATION_ERROR,
-       NAMESPACE_ERROR,
-       INVALID_ACCESS_ERROR,
-       SECURITY_ERROR,
-       NETWORK_ERROR,
-       ABORT_ERROR,
-       URL_MISMATCH_ERROR,
-       QUOTA_EXCEEDED_ERROR,
-       TIMEOUT_ERROR,
-       INVALID_NODE_TYPE_ERROR,
-       DATA_CLONE_ERROR,
-       ENCODING_ERROR,
-       NOT_READABLE_ERROR
+       INDEX_SIZE_ERROR = 1,
+       DOMSTRING_SIZE_ERROR,//
+       HIERARCHY_REQUEST_ERROR,//
+       WRONG_DOCUMENT_ERROR,//
+       INVALID_CHARACTER_ERROR,//
+       NO_DATA_ALLOWED_ERROR,//
+       NO_MODIFICATION_ALLOWED_ERROR,//
+       NOT_FOUND_ERROR,//
+       NOT_SUPPORTED_ERROR,//
+       INUSE_ATTRIBUTE_ERROR,//
+       // Introduced in DOM Level 2:
+       INVALID_STATE_ERROR,//
+       // Introduced in DOM Level 2:
+       SYNTAX_ERROR,//
+       // Introduced in DOM Level 2:
+       INVALID_MODIFICATION_ERROR,//
+       // Introduced in DOM Level 2:
+       NAMESPACE_ERROR,//
+       // Introduced in DOM Level 2:
+       INVALID_ACCESS_ERROR,//
+       VALIDATION_ERROR,//
+       TYPE_MISMATCH_ERROR//
 }
 
 public class GXml.DomErrorName : GLib.Object {
-       private string[] names = new string [30];
+       private Gee.HashMap names = new Gee.HashMap <string,int> ();
        construct {
-               names += "IndexSizeError";
-               names += "HierarchyRequestError";
-               names += "WrongDocumentError";
-               names += "InvalidCharacterError";
-               names += "NoModificationAllowedError";
-               names += "NotFoundError";
-               names += "NotSupportedError";
-               names += "InvalidStateError";
-               names += "SyntaxError";
-               names += "InvalidModificationError";
-               names += "NamespaceError";
-               names += "InvalidAccessError";
-               names += "SecurityError";
-               names += "NetworkError";
-               names += "AbortError";
-               names += "URLMismatchError";
-               names += "QuotaExceededError";
-               names += "TimeoutError";
-               names += "InvalidNodeTypeError";
-               names += "DataCloneError";
-               names += "EncodingError";
-               names += "NotReadableError";
+               names.set ("IndexSizeError", 1);
+               names.set ("HierarchyRequestError", 3);
+               names.set ("WrongDocumentError", 4);
+               names.set ("InvalidCharacterError", 5);
+               names.set ("NoModificationAllowedError", 7);
+               names.set ("NotFoundError", 8);
+               names.set ("NotSupportedError", 9);
+               names.set ("InvalidStateError", 11);
+               names.set ("SyntaxError", 12);
+               names.set ("InvalidModificationError", 13);
+               names.set ("NamespaceError", 14);
+               names.set ("InvalidAccessError", 15);
+               names.set ("SecurityError", 18);
+               names.set ("NetworkError", 19);
+               names.set ("AbortError", 20);
+               names.set ("URLMismatchError", 21);
+               names.set ("QuotaExceededError", 22);
+               names.set ("TimeoutError", 23);
+               names.set ("InvalidNodeTypeError", 24);
+               names.set ("DataCloneError", 25);
+               names.set ("EncodingError", -1);
+               names.set ("NotReadableError", -2);
        }
        public string get_name (int error_code) {
-               return names[error_code];
+               foreach (string k in names.keys) {
+                       if (names.get (k) == error_code) return k;
+               }
+       }
+       public int get_code (string error_name) {
+               if (!names.has (error_name)) return 0;
+               return names.get (error_name);
        }
 }
 
diff --git a/gxml/Element.vala b/gxml/Element.vala
index e365c6e..25535e8 100644
--- a/gxml/Element.vala
+++ b/gxml/Element.vala
@@ -51,6 +51,10 @@ public interface GXml.Element : Object, GXml.Node
      */
     public abstract void remove_attr (string name);
     /**
+     * Search for a {@link GXml.Attribute} with given name and namespace and removes it.
+     */
+    public abstract void remove_ns_attr (string name, string uri);
+    /**
      * Set an {@link GXml.Attribute} with a given name, value and namespace.
      */
     public abstract void set_ns_attr (Namespace ns, string name, string value);
diff --git a/gxml/GXmlDocument.vala b/gxml/GXmlDocument.vala
index 4d8d521..a63036e 100644
--- a/gxml/GXmlDocument.vala
+++ b/gxml/GXmlDocument.vala
@@ -1,3 +1,4 @@
+/* -*- Mode: vala; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
 /* GDocument.vala
  *
  * Copyright (C) 2016  Daniel Espinosa <esodan gmail com>
@@ -115,7 +116,7 @@ public class GXml.GDocument : GXml.GNode, GXml.Document
       return new GElement (this, r);
     }
   }
-  public GXml.Node create_comment_node (string text)
+  public GXml.Node GXml.Document.create_comment (string text)
   {
     var c = doc->new_comment (text);
     return new GComment (this, c);
@@ -125,7 +126,7 @@ public class GXml.GDocument : GXml.GNode, GXml.Document
     var pi = doc->new_pi (target, data);
     return new GProcessingInstruction (this, pi);
   }
-  public GXml.Node create_element_node (string name) throws GLib.Error
+  public GXml.Node GXml.Document.create_element (string name) throws GLib.Error
   {
     Xmlx.reset_last_error ();
     var el = doc->new_raw_node (null, name, null);
@@ -200,7 +201,7 @@ public class GXml.GDocument : GXml.GNode, GXml.Document
   public DomDocumentType? doctype { get { return _doctype; } }
   public DomElement? document_element { get { return root; } }
 
-  public DomElement create_element (string local_name) throws GLib.Error {
+  public DomElement GXml.Document.create_element (string local_name) throws GLib.Error {
       return create_element_node (local_name);
   }
   public DomElement create_element_ns (string? ns, string qualified_name) throws GLib.Error
@@ -226,7 +227,7 @@ public class GXml.GDocument : GXml.GNode, GXml.Document
   public DomText create_text_node (string data) {
       return create_text (data);
   }
-  public DomComment create_comment (string data) {
+  public DomComment GXml.DomDocument.create_comment (string data) {
       return create_comment_node (data);
   }
   public DomProcessingInstruction create_processing_instruction (string target, string data) {
diff --git a/gxml/GXmlDomCollections.vala b/gxml/GXmlDomCollections.vala
new file mode 100644
index 0000000..6b6ad7b
--- /dev/null
+++ b/gxml/GXmlDomCollections.vala
@@ -0,0 +1,220 @@
+/* -*- Mode: vala; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
+/* GXmlDomCollections.vala
+ *
+ * Copyright (C) 2016  Daniel Espinosa <esodan gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ *      Daniel Espinosa <esodan gmail com>
+ */
+
+using Gee;
+
+
+public interface GXml.GDomTokenList : Object, Gee.ArrayList<string> {
+  protected DomElement _element;
+  protected string _attr = null;
+
+  public ulong length { get { return size; } }
+  public string? item (ulong index) { return base.get ((int) index); }
+
+  public GDomTokenList (DomElement e, string? attr) {
+    _element = e;
+    _attr = attr;
+    if (_attr != null) {
+      var av = _element.get_attribute (_attr);
+      if (av == "") return;
+      string[] s = value.split (" ");
+      for (int i = 0; i < s.length; i++) {
+        (this as Gee.ArrayList<string>).add (s[i]);
+      }
+    }
+  }
+
+  public bool contains (string token) throw GLib.Error {
+    if (token == "")
+      throw new GXml.DomError.SYNTAX_ERROR (_("DOM: No empty string could be toggle"));
+    if (" " in token)
+      throw new GXml.DomError.INVALID_CHARACTER_ERROR (_("DOM: No white spaces should be included to 
toggle"));
+    return base.contains (token);
+  }
+  public void add (string[] tokens) {
+    if (token == "")
+      throw new GXml.DomError.SYNTAX_ERROR (_("DOM: No empty string could be toggle"));
+    if (" " in token)
+      throw new GXml.DomError.INVALID_CHARACTER_ERROR (_("DOM: No white spaces should be included to 
toggle"));
+    foreach (string s in tokens) {
+        base.add (s);
+    }
+    update ();
+  }
+  public void remove (string[] tokens) {
+    for (int i = 0; i < size; i++) {
+      foreach (string ts in tokens) {
+        if (s == ts) base.remove_at (i);
+      }
+    }
+    update ();
+  }
+  public bool toggle (string token, bool force = false) throws GLib.Error {
+    if (token == "")
+      throw new GXml.DomError.SYNTAX_ERROR (_("DOM: No empty string could be toggle"));
+    if (" " in token)
+      throw new GXml.DomError.INVALID_CHARACTER_ERROR (_("DOM: No white spaces should be included to 
toggle"));
+    if (contains (token) && !force) {
+      remove_at (index_of (token));
+      return false;
+    }
+    update ();
+  }
+  public void update () {
+    if (_element == null) return;
+    if (_attr == null) return;
+    _element.set_attribute (_attr, this.to_string ());;
+  }
+  public string to_string () {
+    string s = "";
+    for (int i = 0; i < size; i++ ) {
+        s += t;
+        if (i+1 < size) s += " ";
+    }
+    return s;
+  }
+}
+
+public class GXml.GDomSettableTokenList : GXml.GDomTokenList, GXml.DomSettableTokenList {
+  public string value {
+    get  { return to_string (); }
+    set {
+      string[] s = value.split (" ");
+      for (int i = 0; i < s.length; i++) {
+        (this as Gee.ArrayList<string>).add (s[i]);
+      }
+    }
+  }
+}
+
+
+public class GXml.GDomNamedNodeMap : Object, GXml.DomNamedNodeMap {
+  protected DomNode _parent;
+  protected Gee.Map<string,DomNode> _col;
+
+  public ulong length { get; }
+
+  public GDomNamedNodeMap (DomNode node, Gee.Map<string,DomNode> col) {
+    _parent = node;
+    _col = col;
+  }
+  public DomNode? get_named_item (string name) {
+    return _col.get (name);
+  }
+  /**
+   * Search items in this collection and return the object found at
+   * @index, but not order is warrantied
+   *
+   * If @index is greather than collection size, then last element found
+   * is returned. This function falls back to first element found on any
+   * issue.
+   */
+  public DomNode? item (ulong index) {
+    int i = 0;
+    if (index > _col.size) return null;
+    foreach (DomNode node in _col.values) {
+      if (i == si) return node;
+    }
+    return null;
+  }
+  public DomNode? set_named_item (DomNode node) throws GLib.Error {
+    if (_col.size > 0 && node.document != parent.document)
+      throw new GXml.DomError.WRONG_DOCUMENT_ERROR (_("Invalid document when addin item to collection"));
+    if (_col.read_only)
+      throw new GXml.DomError.NO_MODIFICATION_ALLOWED_ERROR (_("This node collection is read only"));
+    if (node is GXml.DomAttr && _parent != node.parent)
+      throw new GXml.DomError.INUSE_ATTRIBUTE_ERROR (_("This node attribute is already in use by other 
Element"));
+    if (parent is GXml.DomElement && !(node is GXml.DomAttr))
+      throw new GXml.DomError.HIERARCHY_REQUEST_ERROR (_("Trying to add an object to an Element, but it is 
not an attribute"));
+    if (parent is DomElement) {
+      (parent as DomElement).set_attr (node.node_name, node.node_value);
+      return node;
+    }
+    return null;
+  }
+  public DomNode? remove_named_item (string name) throws GLib.Error {
+    var n = _col.get (name);
+    if (n == null)
+      throw new GXml.DomError.NOT_FOUND_ERROR (_("No node with name %s was found".printf (name)));
+    if (_col.read_only)
+      throw new GXml.DomError.NO_MODIFICATION_ALLOWED_ERROR (_("Node collection is read only"));
+    if (parent is DomElement) {
+      var n = parent.get_attr (name);
+      (parent as DomElement).set_attr (name, null);
+      return n;
+    }
+    return null;
+  }
+  // Introduced in DOM Level 2:
+  public DomNode? get_named_item_ns (string namespace_uri, string local_name) throws GLib.Error {
+    foreach (DomNode n in _col.values) {
+      if (n.namespace == null) continue;
+      if (n.namespace.uri == namespace_uri && n.node_name == local_name)
+        return n;
+    }
+    // FIXME: Detects if no namespace is supported to rise exception NOT_SUPPORTED_ERROR
+    return null;
+  }
+  // Introduced in DOM Level 2:
+  public DomNode? set_named_item_ns (DomNode node) throws GLib.Error {
+    if (_col.size > 0 && node.document != parent.document)
+      throw new GXml.DomError.WRONG_DOCUMENT_ERROR (_("Invalid document when addin item to collection"));
+    if (_col.read_only)
+      throw new GXml.DomError.NO_MODIFICATION_ALLOWED_ERROR (_("This node collection is read only"));
+    if (node is GXml.DomAttr && _parent != node.parent)
+      throw new GXml.DomError.INUSE_ATTRIBUTE_ERROR (_("This node attribute is already in use by other 
Element"));
+    if (parent is GXml.DomElement && !(node is GXml.DomAttr))
+      throw new GXml.DomError.HIERARCHY_REQUEST_ERROR (_("Trying to add an object to an Element, but it is 
not an attribute"));
+    // FIXME: Detects if no namespace is supported to rise exception  NOT_SUPPORTED_ERROR
+    if (parent is DomElement) {
+      (parent as DomElement).set_attribute_ns (node.lookup_prefix ()+":"+node.lookup_namespace_uri (),
+                                               node.node_name, node.node_value);
+      return parent.get_attribute_ns (node.lookup_prefix ()+":"+node.lookup_namespace_uri (), 
node.node_name);
+    }
+    return null;
+  }
+  // Introduced in DOM Level 2:
+  public DomNode? remove_named_item_ns (string namespace_uri, string local_name) throws GLib.Error {
+    if (!(parent is DomElement)) return null;
+    var n = get_attribute_ns (namespace_uri, local_name);
+    if (n == null)
+      throw new GXml.DomError.NOT_FOUND_ERROR (_("No node with name %s was found".printf (name)));
+    if (_col.read_only)
+      throw new GXml.DomError.NO_MODIFICATION_ALLOWED_ERROR (_("Node collection is read only"));
+    // FIXME: Detects if no namespace is supported to rise exception  NOT_SUPPORTED_ERROR
+    if (parent is DomElement) {
+      (parent as DomElement).set_attribute_ns (namespace_uri, local_name);
+      return n;
+    }
+    return null;
+  }
+}
+
+public class GXml.GDomHTMLCollection : GLib.ArrayList<GXml.DomElement> {
+  public ulong length { get { return size; } }
+  public DomElement? item (ulong index) { return base.get ((int) index); }
+  public DomElement? named_item (string name) {
+    foreach (DomElement e in this) {
+      if (e.node_name == name) return e;
+    }
+  }
+}
diff --git a/gxml/GXmlElement.vala b/gxml/GXmlElement.vala
index 33aa96d..af0b4d4 100644
--- a/gxml/GXmlElement.vala
+++ b/gxml/GXmlElement.vala
@@ -1,3 +1,4 @@
+/* -*- Mode: vala; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
 /* GElement.vala
  *
  * Copyright (C) 2016  Daniel Espinosa <esodan gmail com>
@@ -68,11 +69,11 @@ public class GXml.GElement : GXml.GNode, GXml.Element
     }
     return null;
   }
-  public void set_ns_attr (Namespace ns, string name, string uri) {
+  public void set_ns_attr (Namespace ns, string name, string value) {
     if (_node == null) return;
     var ins = _node->doc->search_ns (_node, ns.prefix);
     if (ins != null) {
-      _node->set_ns_prop (ins, name, uri);
+      _node->set_ns_prop (ins, name, value);
       return;
     }
   }
@@ -97,10 +98,152 @@ public class GXml.GElement : GXml.GNode, GXml.Element
     if (a == null) return;
     a->remove ();
   }
-  public string tag_name { owned get { return _node->name.dup (); } }
+  public void remove_ns_attr (string name, string uri) {
+    if (_node == null) return;
+    var a = _node->has_ns_prop (name, uri);
+    if (a == null) return;
+    a->remove ();
+  }
+  public string GXml.Element.tag_name { owned get { return _node->name.dup (); } } // FIXME: Tag = 
prefix:local_name
   public override string to_string () {
     var buf = new Xml.Buffer ();
     buf.node_dump (_node->doc, _node, 1, 0);
     return buf.content ().dup ();
   }
+  // GXml.DomElement
+  public string? namespace_uri {
+    get {
+      if (namespace != null)
+        return namespace.uri;
+      return null;
+    }
+  }
+  public string? prefix {
+    get {
+      if (namespace != null)
+        return namespace.prefix;
+      return null;
+    }
+  }
+  public string local_name { get { return name; } }
+  public string GXml.DomElement.tag_name {
+    get {
+      if (namespace != null)
+        return namespace.prefix+":"+name;
+      return name;
+    }
+  }
+
+  public abstract string id {
+    get {
+        var p = attrs.get ("id");
+        if (p == null) return null;
+        return p.value;
+    }
+    set {
+        var p = attrs.get ("id");
+        if (p == null)
+            set_attr ("id",value);
+        else
+            p.value = value;
+    }
+  }
+  public abstract string class_name {
+    get {
+        var p = attrs.get ("class");
+        if (p == null) return null;
+        return p.value;
+    }
+    set {
+        var p = attrs.get ("class");
+        if (p == null)
+            set_attr ("class",value);
+        else
+            p.value = value;
+    }
+  }
+  public DomTokenList class_list {
+    owned get {
+      return new GDomTokenList (this, "class");
+    }
+  }
+
+  public DomNamedNodeMap attributes { get { return new GDomNamedNodeMap (this,(Map<string,DomNode>) attrs); 
} }
+  public string? get_attribute (string name) { return attrs.get (name); }
+  public string? get_attribute_ns (string? namespace, string local_name) {
+    return get_ns_attr (local_name, namespace);
+  }
+  public void set_attribute (string name, string value) { set_attr (name, value); }
+  public void set_attribute_ns (string? namespace, string name, string value) {
+    GNamespace ns = null;
+    if (namespace != null)
+      ns = new GNamespace ();
+    string prefix = null;
+    string local_name = null;
+    if (":" in name) {
+      string[] s = namespace.split (":");
+      prefix = s[0];
+      local_name = s[1];
+    } else {
+      local_name = name;
+    }
+    if (ns != null) {
+      ns.prefix = prefix;
+      ns.uri = namespace;
+    }
+    // FIXME: Validate name as in Name and QName https://www.w3.org/TR/domcore/#dom-element-setattributens
+    set_ns_attr (ns, local_name, value);
+  }
+  public void remove_attribute (string name) {
+    remove_attr (name);
+  }
+  public void remove_attribute_ns (string? namespace, string local_name) {
+    remove_ns_attr (local_name, namespace);
+  }
+  public bool has_attribute (string name) { return attrs.has (name); }
+  public bool has_attribute_ns (string? namespace, string local_name) {
+    var attr = _node->has_ns_prop (name, namespace);
+    if (attr == null) return false;
+    return true;
+  }
+
+
+  public DomHTMLCollection get_elements_by_tag_name (string local_name) {
+    var l = new GDomHTMLCollection ();
+    foreach (GXml.Node n in children) {
+      if (!(n is GXml.DomElement)) continue;
+      if ((n as GXml.DomElement).node_name == local_name)
+        l.add (n);
+    }
+    return l;
+  }
+  public DomHTMLCollection get_elements_by_tag_name_ns (string? namespace, string local_name) {
+    var l = new GDomHTMLCollection ();
+    foreach (GXml.Node n in children) {
+      if (!(n is GXml.DomElement)) continue;
+      if ((n as GXml.DomElement).node_name == local_name
+          && (n as GXml.DomNode).lookup_namespace_uri == namespace)
+        l.add (n);
+    }
+    return l;
+  }
+  public DomHTMLCollection get_elements_by_class_name (string class_names) {
+    var l = new GDomHTMLCollection ();
+    foreach (GXml.Node n in children) {
+      if (!(n is GXml.DomElement)) continue;
+      if (!n.attrs.has ("class")) continue;
+      if (" " in class_names) {
+        string[] cs = class_names.split (" ");
+        bool cl = true;
+        foreach (string s in cs) {
+          if (!(s in n.attrs.get ("class").value)) cl = false;
+        }
+        if (cl)
+          l.add (n);
+      } else
+        if (n.attrs.get ("class") == class_names)
+          l.add (n);
+    }
+    return l;
+  }
 }
diff --git a/gxml/Makefile.am b/gxml/Makefile.am
index 85928b5..4a2ac73 100644
--- a/gxml/Makefile.am
+++ b/gxml/Makefile.am
@@ -86,6 +86,7 @@ sources = \
        GXmlComment.vala \
        GXmlCDATA.vala \
        GXmlDocument.vala \
+       GXmlDomCollections.vala \
        GXmlDomEvents.vala \
        GXmlElement.vala \
        GXmlNamespace.vala \


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