DEV Community

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

Posted on • Edited on

3 3

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

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

Billboard image

Create up to 10 Postgres Databases on Neon's free plan.

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Try Neon for Free →

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay