DEV Community

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

Posted on • Updated 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)

An Animated Guide to Node.js Event Loop

Node.js doesn’t stop from running other operations because of Libuv, a C++ library responsible for the event loop and asynchronously handling tasks such as network requests, DNS resolution, file system operations, data encryption, etc.

What happens under the hood when Node.js works on tasks such as database queries? We will explore it by following this piece of code step by step.