XML Vala Sample
The libxml2 binding is somewhat odd to use from Vala since you must do manual memory management via pointers. An alternative is to use the GObject-based abstraction layer/wrapper GXml, written in Vala.
Anyway, here's the sample:
/*
* Various operations with libxml2: Parsing and creating an XML file
*/
using Xml;
class XmlSample {
// Line indentation
private int indent = 0;
private void print_indent (string node, string content, char token = '+') {
string indent = string.nfill (this.indent * 2, ' ');
stdout.printf ("%s%c%s: %s\n", indent, token, node, content);
}
public void parse_file (string path) {
// Parse the document from path
Xml.Doc* doc = Parser.parse_file (path);
if (doc == null) {
stderr.printf ("File %s not found or permissions missing", path);
return;
}
// Get the root node. notice the dereferencing operator -> instead of .
Xml.Node* root = doc->get_root_element ();
if (root == null) {
// Free the document manually before returning
delete doc;
stderr.printf ("The xml file '%s' is empty", path);
return;
}
print_indent ("XML document", path, '-');
// Print the root node's name
print_indent ("Root node", root->name);
// Let's parse those nodes
parse_node (root);
// Free the document
delete doc;
}
private void parse_node (Xml.Node* node) {
this.indent++;
// Loop over the passed node's children
for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
// Spaces between tags are also nodes, discard them
if (iter->type != ElementType.ELEMENT_NODE) {
continue;
}
// Get the node's name
string node_name = iter->name;
// Get the node's content with <tags> stripped
string node_content = iter->get_content ();
print_indent (node_name, node_content);
// Now parse the node's properties (attributes) ...
parse_properties (iter);
// Followed by its children nodes
parse_node (iter);
}
this.indent--;
}
private void parse_properties (Xml.Node* node) {
// Loop over the passed node's properties (attributes)
for (Xml.Attr* prop = node->properties; prop != null; prop = prop->next) {
string attr_name = prop->name;
// Notice the ->children which points to a Node*
// (Attr doesn't feature content)
string attr_content = prop->children->content;
print_indent (attr_name, attr_content, '|');
}
}
public static string create_simple_xml () {
Xml.Doc* doc = new Xml.Doc ("1.0");
Xml.Ns* ns = new Xml.Ns (null, "", "foo");
ns->type = Xml.ElementType.ELEMENT_NODE;
Xml.Node* root = new Xml.Node (ns, "simple");
doc->set_root_element (root);
root->new_prop ("property", "value");
Xml.Node* subnode = root->new_text_child (ns, "subnode", "");
subnode->new_text_child (ns, "textchild", "another text" );
subnode->new_prop ("subprop", "escaping \" and < and >" );
Xml.Node* comment = new Xml.Node.comment ("This is a comment");
root->add_child (comment);
string xmlstr;
// This throws a compiler warning, see bug 547364
doc->dump_memory (out xmlstr);
delete doc;
return xmlstr;
}
}
int main (string[] args) {
if (args.length < 2) {
stderr.printf ("Argument required!\n");
return 1;
}
// Initialisation, not instantiation since the parser is a static class
Parser.init ();
string simple_xml = XmlSample.create_simple_xml ();
stdout.printf ("Simple XML is:\n%s\n", simple_xml);
var sample = new XmlSample ();
// Parse the file listed in the first passed argument
sample.parse_file (args[1]);
// Do the parser cleanup to free the used memory
Parser.cleanup ();
return 0;
}
Compile
$ valac --pkg libxml-2.0 xmlsample.vala $ ./xmlsample
XML Text Writer example
This example shows how to use xmlTextWriter from libxml2 in Vala.
NOTE: Vala 0.8 required for this example.
void main () {
var writer = new Xml.TextWriter.filename ("test.xml");
writer.set_indent (true);
writer.set_indent_string ("\t");
writer.start_document ();
writer.start_element ("root_element");
writer.start_attribute ("base64attribute");
writer.write_base64 ("test", 0, 4);
writer.end_attribute ();
writer.write_attribute ("alpha", "abcdef..");
writer.write_element ("element", "content");
writer.write_element_ns ("ns", "elementWithNS", "http://www.example.org/test/ns", "contentNS");
writer.write_comment ("My comment!");
writer.format_element_ns ("ns", "elementWithFormattedContent", "http://www.example.org/test/ns", "One: %d", 10);
writer.start_element("cdataContent");
writer.start_cdata();
writer.format_string("%s beer on the wall..", "One");
writer.end_cdata();
writer.end_element();
writer.end_element();
writer.end_document();
writer.flush();
}
XPath Sample
This example based on http://charette.no-ip.com:81/programming/2010-01-03_LibXml2/2010-01-03_LibXml2.cpp .
Read the original for comments.
using Xml.XPath;
using Xml;
class xpathsample {
public static int main(string[] args) {
Parser.init ();
string path = "example.xml";
Xml.Doc* doc = Parser.parse_file (path);
if(doc==null) print("failed to read the .xml file\n");
Context ctx = new Context(doc);
if(ctx==null) print("failed to create the xpath context\n");
Xml.XPath.Object* obj = ctx.eval_expression("/Example/Objects/Pet");
if(obj==null) print("failed to evaluate xpath\n");
Xml.Node* node = null;
if ( obj->nodesetval != null && obj->nodesetval->item(0) != null ) {
node = obj->nodesetval->item(0);
print("Found the node we want");
} else {
print("failed to find the expected node");
}
Xml.Attr* attr = null;
attr = node->properties;
while ( attr != null )
{
print("Attribute: \tname: %s\tvalue: %s\n", attr->name, attr->children->content);
attr = attr->next;
}
//...
delete obj;
delete doc;
return 0;
}
}
Compile
$ valac --pkg libxml-2.0 xpathsample.vala $ ./xpathsample
XML Text Reader Sample
This example shows how to use xmlTextReader from libxml2 in Vala and is based on http://www.xmlsoft.org/examples/reader1.c .
Note: It's a simple translation of the c-code and it works for me just the same but could still have memory errors, because I do not know how I give the memory free, maybe the libxml-wrapper makes it automatically, but I'm not sure.
/**
* section: xmlReader
* synopsis: Parse an XML file with an xmlReader
* purpose: Demonstrate the use of xmlReaderForFile() to parse an XML file
* and dump the informations about the nodes found in the process.
* original: This example is based on http://www.xmlsoft.org/examples/reader1.c
* copy: Please see the original file for Copyright and Author.
*/
using Xml;
/**
* processNode:
* @reader: the xmlReader
*
* Dump information about the current node
*/
static void
processNode(Xml.TextReader reader) {
var name = reader.const_name();
if (name == null)
name = "--";
var val = reader.const_value();
print("%d %d %s %d %d",
reader.depth(),
reader.node_type(),
name,
reader.is_empty_element(),
reader.has_value());
if (val == null)
print("\n");
else {
if (val.length > 40)
print(" %.40s...\n", val);
else
print(" %s\n", val);
}
}
/**
* streamFile:
* @uri: the file name to parse
*
* Parse and print information about an XML file.
*/
static void
streamFile(string uri) {
int ret;
var reader = new Xml.TextReader.filename(uri);
if (reader != null) {
ret = reader.read();
while (ret == 1) {
processNode(reader);
ret = reader.read();
}
reader = null; // TODO fixme c-function is xmlFreeTextReader(reader);
if (ret != 0) {
printerr("%s : failed to parse\n", uri);
}
} else {
printerr("Unable to open %s\n", uri);
}
}
int main(string[] args) {
if (args.length != 2)
return(1);
streamFile(args[1]);
/*
* Cleanup function for the XML library.
*/
Xml.Parser.cleanup();
/*
* this is to debug memory for regression tests
*/
// TODO fixme c-function is xmlMemoryDump();
return(0);
}
Compile
$ valac --pkg libxml-2.0 reader1.vala $ ./reader1 <filename>