/* * Copyright (C) 2007,2008 Nicolas Joseph * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 3 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /** * @bug[vala] : undeclared typedef in C code. */ [NoArrayLength] public static delegate void GMarkupParserStartElementFunc (GLib.MarkupParseContext context, string element_name, string[] attribute_names, string[] attribute_values, pointer user_data) throws GLib.MarkupError; public static delegate void GMarkupParserEndElementFunc (GLib.MarkupParseContext context, string element_name, pointer user_data) throws GLib.MarkupError; public static delegate void GMarkupParserTextFunc (GLib.MarkupParseContext context, string text, ulong text_len, pointer user_data) throws GLib.MarkupError; private class MarkupDomContext : GLib.Object { public int level; public string filename; public MarkupDomNode root; public MarkupDomNode last_root; public MarkupDomNode last_node; public MarkupDomNode current; construct { this.level = 0; this.filename = null; this.root = null; this.last_root = null; this.last_node = null; this.current = null; } } public class MarkupDomNode : GLib.Object { public string name; public string content; public int level; public GLib.HashTable attributs = new GLib.HashTable (GLib.str_hash, GLib.str_equal); public MarkupDomNode parent; public MarkupDomNode child; public MarkupDomNode next; public MarkupDomNode prev; public string filename; private static weak GLib.String indent (GLib.String s, int niv) { for (int i = 0; i < niv - 1; i++) { s.append ("\t"); } return s; } private static void add_attr (pointer key, pointer value, pointer user_data) { weak GLib.String str = (GLib.String)user_data; str.append_printf (" %s=\"%s\"", key, value); } private static string get_xml_ (MarkupDomNode root) { GLib.String str = new GLib.String (""); if (root != null) { indent (str, root.level); str.append_printf ("<%s", root.name); int i = 0; root.attributs.for_each (add_attr, str); str.append (">\n"); if (root.content != null) { indent (str, root.level + 1); str.append_printf ("%s\n", root.content); } str.append (get_xml_ (root.child)); indent (str, root.level); str.append_printf ("\n", root.name); str.append (get_xml_ (root.next)); } return str.str; } private static MarkupDomNode get_element_by_name_ (MarkupDomNode root, string! name) { MarkupDomNode node = null; if (root != null) { if (root.name == name) { node = root; } else { node = get_element_by_name_ (root.child, name); if (node == null) { node = get_element_by_name_ (root.next, name); } } } return node; } construct { this.name = null; this.content = null; this.level = 0; this.parent = null; this.child = null; this.next = null; this.prev = null; this.filename = null; } /** * @return: XML string. * * Get XML file contents from a #MarkupDomNode. */ public string get_xml () { return get_xml_ (this); } /** * @name: search tag name. * * @return A #MarkupDomNode. * * Return #MarkupDomNode with name #name. */ public MarkupDomNode get_element_by_name (string! name) { return get_element_by_name_ (this, name); } /** * @path: search tag path. * * @return A #MarkupDomNode. * * Return #MarkupDomNode with path #path. */ public MarkupDomNode get_element_by_path (string! path) { MarkupDomNode root = null; string[] names = null; names = path.split ("/", -1); for (int i = 0; names[i] != null; i++) { MarkupDomNode tmp = null; tmp = this.get_element_by_name (names[i]); if (tmp == null) { root = null; break; } else { root = tmp; } } return root; } } public class MarkupDom : GLib.Object { [NoArrayLength] private static void xml_start_element (GLib.MarkupParseContext context, string element_name, string[] attribute_names, string[] attribute_values, pointer user_data) throws GLib.MarkupError { MarkupDomContext* dom_context = user_data; MarkupDomNode node = new MarkupDomNode (); dom_context->level++; dom_context->current = node; if (dom_context->root == null) { dom_context->root = node; } node.name = element_name; node.level = dom_context->level; node.filename = dom_context->filename; if (dom_context->last_node != null && dom_context->last_node.level == node.level) { node.prev = dom_context->last_node; dom_context->last_node.next = node; } for (int i = 0; attribute_names[i] != null; i++) { node.attributs.insert (attribute_names[i], attribute_values[i]); } node.parent = dom_context->last_root; if (dom_context->last_root != null && dom_context->last_root.child == null) { dom_context->last_root.child = node; } dom_context->last_root = node; } private static void xml_end_element (GLib.MarkupParseContext context, string element_name, pointer user_data) throws GLib.MarkupError { MarkupDomContext* dom_context = user_data; dom_context->level--; dom_context->last_root = dom_context->current.parent; dom_context->last_node = dom_context->current; dom_context->current = dom_context->current.parent; } private static void xml_text (GLib.MarkupParseContext context, string text, ulong text_len, pointer user_data) throws GLib.MarkupError { MarkupDomContext* dom_context = user_data; if (dom_context->current.content == null /*&& !str_isspace (text)*/) { dom_context->current.content = text; } } /** * Create a dom tree of @filename content. * * @file_name: name of a file to parse contents from. * * @return A new #MarkupDomNode. */ public static MarkupDomNode load (string! filename) throws GLib.Error { MarkupDomContext context = new MarkupDomContext (); GLib.MarkupParser markup_parser; markup_parser.start_element = xml_start_element; markup_parser.end_element = xml_end_element; markup_parser.text = xml_text; markup_parser.passthrough = null; markup_parser.error = null; context.filename = filename; var markup_parse_context = new GLib.MarkupParseContext (markup_parser, GLib.MarkupParseFlags.TREAT_CDATA_AS_TEXT, context, null); string contents; size_t length; GLib.FileUtils.get_contents (filename, out contents, out length); markup_parse_context.parse (contents, (long)length); return context.root; } }