DEV Community

Cover image for Counting XML elements with xmllint
Tobias Haindl
Tobias Haindl

Posted on • Edited on

Counting XML elements with xmllint

This week I needed to validate the number of entries in an XML file.
After a short Google search I came across xmllint.
This handy little CLI tool looked like the perfect tool for this job, so I tried it out immediately.
Unfortunately it took me some time to figure out how I can use it with my XML file.

Here is why:
Counting XML entries in an XML file without a namespace is pretty straightforward.
Let’s assume our XML file has the following structure and we want to find the number of entries.

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
   <record>
      <id>1</id>
      <first_name>Dru</first_name>
      <last_name>Greenway</last_name>
      <email>dgreenway0@technorati.com</email>
      <ip_address>168.235.172.238</ip_address>
   </record>
   <record>
      <id>2</id>
      <first_name>Agnesse</first_name>
      <last_name>Janousek</last_name>
      <email>ajanousek1@unblog.fr</email>
      <ip_address>62.116.98.136</ip_address>
   </record>
</dataset>
Enter fullscreen mode Exit fullscreen mode

One can simply pass a xpath expression to xmllint and make use of the count function:

xmllint --xpath "count(//record)" example.xml

For more information on xpath syntax checkout: https://www.w3schools.com/xml/xpath_syntax.asp

In the example from above the result would be 2.

Unfortunately my XML file looked a bit different since it had a default namespace defined.
If we change <dataset> to <dataset xmlns="http://www.some-custom-namespace.org">.
The same command:
xmllint --xpath "count(//record)" example.xml

returns 0 since the xpath expression does not match any element.
How can we solve this problem?

Option 1

Use the interactive shell:

xmllint --shell example_with_ns.xml

Set the namespace to the referenced namespace in your file, in our example:
setns x=http://www.some-custom-namespace.org

Execute xpath command:
xpath count(//x:record) ... prints 2

Note the x prefix!
This prefix must match the variable chosen in the setns command.

Option 2

Make use of the local-name function:

xmllint -xpath "count(//*[local-name()='record'])" example_with_ns.xml ... prints 2

Sources:
https://gist.github.com/bitsgalore/3e403b02f776f03444c0622cb3b08b56
https://stackoverflow.com/a/8266075/3533210

Photo credit:
Photo by Josh Appel on Unsplash

Top comments (0)