XML Vala Sample
The libxml2 binding is somewhat odd to use from Vala/ Genie, you must do manual memory management via pointers. An abstraction layer/wrapper to the binding would certainly help make things easier. Anyway, here's the sample:
/*
* Various operations with libxml2: Parsing and creating an XML file
*/
uses
Xml
class XmlSample
// Line indentation
indent : int = 0
def private print_indent (node : string, content : string, token : char = '+')
indent : string = string.nfill (this.indent * 2, ' ')
stdout.printf ("%s%c%s: %s\n", indent, token, node, content)
def parse_file (path : string)
// Parse the document from path
doc : Xml.Doc* = Parser.parse_file (path)
if doc is null
stderr.printf ("File %s not found or permissions missing", path)
return
// Get the root node. notice the dereferencing operator -> instead of .
root : Xml.Node* = doc->get_root_element ()
if root is 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
def private parse_node ( node : Xml.Node*)
this.indent++
// Loop over the passed node's children
iter : Xml.Node* = node->children
while (iter=iter->next) is not null
// Spaces between tags are also nodes, discard them
if iter->type is not ElementType.ELEMENT_NODE
continue
// Get the node's name
node_name : string = iter->name
// Get the node's content with <tags> stripped
node_content : string = 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)
// go next
iter = iter->next
this.indent--
def private parse_properties (node : Xml.Node*)
// Loop over the passed node's properties (attributes)
p : Xml.Attr* = node->properties
while p is not null
attr_name : string = p->name
// Notice the ->children which points to a Node*
// (Attr doesn't feature content)
attr_content : string = p->children->content
print_indent (attr_name, attr_content, '|')
// go next
p = p->next
def static create_simple_xml () : string
doc : Xml.Doc* = new Xml.Doc ("1.0")
ns : Xml.Ns* = new Xml.Ns (null, "", "foo")
ns->type = Xml.ElementType.ELEMENT_NODE
root : Xml.Node* = new Xml.Node (ns, "simple")
doc->set_root_element (root)
root->new_prop ("property", "value")
subnode : Xml.Node* = root->new_text_child (ns, "subnode", "")
subnode->new_text_child (ns, "textchild", "another text" )
subnode->new_prop ("subprop", "escaping \" and < and >" )
comment : Xml.Node* = new Xml.Node.comment ("This is a comment")
root->add_child (comment)
xmlstr : string
// This throws a compiler warning, see bug 547364
doc->dump_memory (out xmlstr)
delete doc
return xmlstr
init
if args.length < 2
stderr.printf ("Argument required!\n")
return
// Initialisation, not instantiation since the parser is a static class
Parser.init ()
simple_xml : string = 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
Compile and Run
$ valac --pkg libxml-2.0 xmlsample.vala $ ./xmlsample
init
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()
}}
{{{
$ valac --pkg libxml-2.0 xmlwriter.vala
$ ./xmlwriter
The example produces following output in test.xml:
<?xml version="1.0"?> <root_element base64attribute="dGVzdA==" alpha="abcdef.."> <element>content</element> <ns:elementWithNS xmlns:ns="http://www.example.org/test/ns">contentNS</ns:elementWithNS> <!--My comment!--> <ns:elementWithFormattedContent xmlns:ns="http://www.example.org/test/ns">One: 10</ns:elementWithFormattedContent> <cdataContent><![CDATA[One beer on the wall..]]></cdataContent> </root_element>