# Released EzXML.jl - a new package for XML/HTML

**URL:** <https://discourse.julialang.org/t/released-ezxml-jl-a-new-package-for-xml-html/370>\
**Category:** Community\
**Tags:** announcement\
**Created:** [November 17, 2016, 1:16am UTC](https://discourse.julialang.org/t/released-ezxml-jl-a-new-package-for-xml-html/370 "2016-11-17T01:16:40Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![bicycle1885](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bicycle1885/32/107_2.png) [@bicycle1885](https://discourse.julialang.org/u/bicycle1885)\
**Post date:** [November 17, 2016, 1:16am UTC](https://discourse.julialang.org/t/released-ezxml-jl-a-new-package-for-xml-html/370/1 "2016-11-17T01:16:40Z")

</div>

I released a new package, [EzXML.jl](https://github.com/bicycle1885/EzXML.jl),  
XML/HTML handling tools for primates. The initial release was about a week ago,  
and it started to support Windows from the latest tagged version (v0.2.0).

But as you know, we already have several packages for XML. So, why did I make yet  
another? The main reason is because I’m not satisfied with the APIs of other  
packages. Also, I wanted to support more features. Highlighted features are:

- Consistent and Julian APIs.
- Intuitive namespace handling.
- Searching elements with XPath.
- Streaming reader for large files.
- Automatic memory management.

Let me explain a little bit more for each feature here. Since EzXML.jl and  
LightXML.jl are both built on top of libxml2 it would be better to compare them  
by examples. I hope it will convince you of its usefulness.

Here I compared some APIs of EzXML.jl with those of LightXML.jl:

```julia
# EzXML.jl version.
using EzXML
xdoc = readxml("ex1.xml")
xroot = root(xdoc)
for c in eachnode(xroot)
    println(nodetype(c))
    if iselement(c)
        println(name(c))
    end
end

# LightXML.jl version.
using LightXML
xdoc = parse_file("ex1.xml")
xroot = root(xdoc)
for c in child_nodes(xroot)
    println(nodetype(c))
    if is_elementnode(c)
        e = XMLElement(c)
        println(name(e))
    end
end

```

As you noticed, some functions have a different name. For example, `parse_file`  
is renamed as `readxml` because “read” is used consistently in the standard  
library to read data from a file. “parse” is reserved for parsing a string and  
the function is named as `parsexml`. `child_nodes` is also renamed as  
`eachnode`, which mimics the names of `Base.eachindex` and `Base.eachline`.  
Types have different names, too. In EzXML.jl, `Node` is the only type that  
represents a node in XML while LightXML.jl has `XMLElement`, `XMLNode` and  
`XMLAttr`. A whole XML document is stored in a `Document` object but it is just  
a thin wrapper of `Node` and most operations are delegated to the node. So, in a  
sense, everything is a `Node` object in EzXML.jl. No function names exported  
from EzXML.jl have underscores since it’s a Julian way.

Attribute access has a different syntax. In EzXML.jl, `getindex` is overloaded  
for the purpose and you can get an attribute value like  
`elem["attribute-name"]`. Of course, `setindex!` and `delete!` are also  
overloaded and work as you expect. Moreover, the attribute name may be prefixed  
by a namespace so you can handle XML documents with namespaces:

```julia
using EzXML
elm = firstelement(xroot)
println(elm["category"])
elm["like"] = "yes"
delete!(elm, "tag")
println(elm)

using LightXML
elm = first(child_elements(xroot))
println(attribute(elm, "category"))
set_attribute(elm, "like", "yes")
# I don't know how I can delete an attribute.
println(elm)

```

The XPath query language is supported in EzXML.jl. `find(<document or node>, <xpath>)` is overloaded to find all matching nodes under a document or a node.  
Like attribute names, namespace prefixes are automatically registered and can be  
used in a query:

```julia
using EzXML
find(xdoc, "/bookstore/book") # A vector of "book" elements under "bookstore".
findfirst(xroot, "book") # The first "book" element under the root.
content.(find(xdoc, "//title")) # A vector of title strings.

```

In addition, streaming reader is supported. This is especially important when  
you want to parse extremely large XML files with limited memory. Since streaming  
reader does not construct an XML document tree in memory, it can parse large  
files with low and constant footprint:

```julia
reader = open(XMLReader, "ex1.xml")
while !done(reader)
    # reader has a current reading node in it.
    if nodetype(reader) == EzXML.READER_ELEMENT && name(reader) == "book"
        println(reader["category"])
    end
    next(reader)
end

```

Another important feature of EzXML.jl superior to LightXML.jl is automatic  
memory management. Nodes of EzXML.jl can automatically free their memories when  
they are no longer accessible from your code. This is far more difficult than  
you may expect because nodes are connected to each other in libxml2, which is  
invisible from Julia’s garbage collecter. EzXML.jl solved (I believe) this  
problem by keeping an owner node in each node object and satisfying uniqueness  
property of node proxy objects. The “uniqueness property” here means that two  
`Node` objects pointing to the same node in a document are identical, which  
enables to avoid “double free” of nodes.

EzXML.jl would be already usable in your projects. However, the package is still  
young (I started it this month) and hence you will encounter problems with it. I  
really welcome any feedbacks from users including bug reports, feature requests,  
and API suggestions. Try it now and let me know what you think!
