Baeldung

Java, Spring and Web Development tutorials

 

Introduction to BaseX
2025-10-28 18:07 UTC by Graham Cox

1. Introduction

In this tutorial, we’ll take a look at the BaseX XML database. We’ll see what it is, how to use it and what we can do with it.

2. What is BaseX?

BaseX is a lightweight, high-performance and scalable XML database. It allows us to store a large amount of data provided in XML format, and then allows us to query and manipulate it using XQuery and XPath.

BaseX offers us a number of different ways we can work with our data, including a GUI application, command line interface, and HTTP APIs, allowing us to provide complex XQuery processing.

3. Running BaseX

Now that we know what BaseX is for, we need to be able to run it. BaseX requires a Java 17 or newer JVM.

We can download the ZIP package from the BaseX download page. This provides everything we need to run BaseX. Once unpacked, we’re ready to start.

Within this package, we’ve got our full database. This includes:

  • In /bin, some scripts for starting the database in various ways.
  • In /data, the actual data that exists within our database.
  • In /lib and /webapp, the actual database software.
  • In /src and /repo, sources for XQuery scripts and modules.

Our BaseX installation can actually manage many separate databases. Each of these exists as a separate directory inside the /data directory.

4. Command Line Interface

BaseX comes with a command-line interface allowing us to work directly with our database. This is useful for administrative actions and quick queries of our data. However, this isn’t designed for concurrent access to a database. We’ll need to rely on the server HTTP APIs for that instead, as we’ll see later.

4.1. Starting the Command Line Interface

We can start the command line interface by executing the ./bin/basex or ./bin/basex.bat command from within our unpacked BaseX installation:

$ ./bin/basex
BaseX 12.0 [Standalone]
Try 'help' to get more information.
>

Once we’ve done this, we have an interface to directly access the databases in our installation.

4.2. Creating and Dropping Databases

We can create a new database using the CREATE DATABASE command:

> CREATE DATABASE baeldung
Database 'baeldung' created in 18.82 ms.

By default, this will create an empty database. However, we can also provide a data file to store in the database:

> CREATE DATABASE baeldung https://files.basex.org/xml/factbook.xml
Database 'baeldung' created in 734.75 ms.

This file can either be locally accessible or on an HTTP URL. The BaseX database will download the file if needed and store it in the new database.

We can now use the LIST command to see our newly created database:

> LIST
Name      Resources  Size     Input Path
----------------------------------------------------------------------
baeldung  1          2304048  https://files.basex.org/xml/factbook.xml
1 database(s).

If we’ve got a database that we don’t want any more, we can drop it with the DROP DATABASE command:

> DROP DATABASE baeldung
Database 'baeldung' was dropped.

Once this is done, the database is immediately dropped.

4.3. Opening a Database

Instead of creating a new database, we often need to access one that already exists. This is done using the OPEN command, specifying the name of the database:

> OPEN baeldung
Database 'baeldung' was opened in 26.67 ms.

Once done, all of our commands are now executed within the context of this database.

When a database is created, it’s also automatically opened for us, so we don’t need to do this in that case.

We can also use the INFO DATABASE command to see which database is currently open:

> INFO DATABASE
Database Properties
 NAME: baeldung
 SIZE: 2251 kB
 NODES: 104627
 DOCUMENTS: 1
 BINARIES: 0
 VALUES: 0
 TIMESTAMP: 2025-10-22T06:40:31.403Z
 UPTODATE: true

This can be useful if we’re switching between databases and need to check where we are at any given time.

4.4. Managing Resources

Now we’ve got a database, we need to add some data to it. All of the data in our database comes in the form of XML files, and there’s no requirement that these different XML files have the same schema. We’re able to store whatever data we have in it, and then we can work with it all.

We can add new files to our database using the ADD command:

> ADD https://files.basex.org/xml/xmark.xml
Resource(s) added in 510.38 ms.

When we do this, we can specify the filename in the same way we do for creating a new database.

All of the files in our database have a name. By default, this is the filename of the file that we’ve just added – xmark.xml in this case. If we want, we can specify the name to use when we add our file using ADD TO:

> ADD TO other.xml https://files.basex.org/xml/xmark.xml
Resource(s) added in 219.85 ms.

We can then see what files exist in our database using the DIR command:

> DIR
Input Path    Type  Content-Type     Size
-------------------------------------------
factbook.xml  xml   application/xml  104627
other.xml     xml   application/xml  5256
xmark.xml     xml   application/xml  5256
3 entries.

If we need to, we can also delete files from our database using the DELETE command:

> DELETE other.xml
1 resource(s) deleted in 3.88 ms.

For this, we need to know the name that the file has within our database. Once we’ve done this, the data is permanently removed and can’t be used any more.

4.5. Querying Resources

Once we’ve got our database with data in it, we need to be able to query this data. We can do this with the XQUERY command. This takes an XQuery query that’s used to retrieve some data:

> XQUERY //item/name
<name>duteous nine eighteen </name>
...
<name>holds perhaps despair amorous </name>
Query "basex" executed in 21.15 ms.

This query is executed against every file in our database, and the matches from all of these are returned.

The matches returned can be as simple or complex as needed. In our above example, this was one element, but we can return entire element trees too if we need:

> xquery //city
<city id="f0_1461" country="f0_136" longitude="10.7" latitude="46.2">
  <name>Tirane</name>
  <population year="87">192000</population>
</city>
...
<city id="f0_36514" country="f0_136" longitude="20.1" latitude="41.1">
  <name>Elbasan</name>
  <population year="87">53000</population>
</city>
Query "basex" executed in 10.79 ms.

By default, this query will work across every file in the current database. If we want, we can specify a different database to access using the db:get() function:

> XQUERY db:get("baeldung")//item/name
<name>duteous nine eighteen </name>
...
<name>holds perhaps despair amorous </name>
Query "basex" executed in 10.0 ms.

Alternatively, we can target a single file within a database using the doc() function:

> XQUERY doc("baeldung/xmark.xml")//item/name
<name>duteous nine eighteen </name>
...
<name>holds perhaps despair amorous </name>
Query "basex" executed in 5.4 ms.

Doing this, we can explore the data as much as we want.

5. HTTP Interface

As well as the command line interface to manage our databases, BaseX also comes with an HTTP server that can expose our data in a variety of ways.

5.1. Starting the HTTP Server

We can start the HTTP server by executing the ./bin/basexhttp or ./bin/basexhttp.bat command from within our unpacked BaseX installation:

-> % ./bin/basexhttp
BaseX 12.0 [HTTP Server]
[main] INFO org.eclipse.jetty.server.Server - jetty-12.0.22; built: 2025-06-02T15:25:31.946Z; git: 335c9ab44a5591f0ea941bf350e139b8c4f5537c; jvm 21.0.2+13-LTS
[main] INFO org.eclipse.jetty.ee9.webapp.StandardDescriptorProcessor - NO JSP Support for /, did not find org.eclipse.jetty.ee9.jsp.JettyJspServlet
[main] INFO org.eclipse.jetty.session.DefaultSessionIdManager - Session workerName=node0
Server was started (port: 1984).
[main] INFO org.eclipse.jetty.server.handler.ContextHandler - Started oeje9n.ContextHandler$CoreContextHandler@2c78d320{BaseX: The XML Database and XQuery Processor,/,b=file:///Users/coxg/source/me/baeldung/basex/webapp/,a=AVAILABLE,h=oeje9n.ContextHandler$CoreContextHandler$CoreToNestedHandler@132e0cc{STARTED}}
[main] INFO org.eclipse.jetty.server.AbstractConnector - Started ServerConnector@512baff6{HTTP/1.1, (http/1.1)}{0.0.0.0:8080}
[main] INFO org.eclipse.jetty.server.Server - Started oejs.Server@77fbd92c{STARTING}[12.0.22,sto=0] @613ms
HTTP Server was started (port: 8080).
HTTP STOP Server was started (port: 8081).

This actually starts three network servers, by default listening on ports 1984, 8080 and 8081. The one on port 8080 is the interesting one, because this is our HTTP server that we can send queries to.

5.2. Authentication

This server requires authentication to make sure our data is safe. By default, there’s an admin account with a password that’s generated the first time the HTTP server is started. We can find the password for this in the log files, located in /data/.logs:

$ cat data/.logs/2025-10-20.log
07:50:10.457	SERVER	admin	OK	Server was started (port: 1984).
07:50:10.505	SERVER	admin	INFO	Initial admin password (change after first login): 29a058d7-9dc3-4d7a-bab1-8380eca78e42

If we wish, we can change this using the PASSWORD command from the command line client:

> PASSWORD NewPassword
Password of user 'admin' changed.

All of our HTTP requests to the server need to provide credentials using HTTP basic authentication. These consist of our username – “admin” – and password, correctly encoded as expected for basic authentication. Our HTTP client should be able to handle this automatically for us.

5.3. Accessing Databases

We can list the available databases by making an HTTP call to the /rest endpoint on our server:

GET /rest HTTP/1.1
Authorization: Basic YWRtaW46TmV3UGFzc3dvcmQ=

The response will be an XML document describing all of the databases that we’ve created:

HTTP/1.1 200 OK
Content-Type: application/xml; charset=UTF-8
<databases xmlns="http://basex.org/rest">
  <database resources="3" size="2796460">baeldung</database>
</databases>

5.4. Accessing Resources

We can access a specific database by including it on the URL – for example, /rest/baeldung. If we call this directly, we’ll see a list of all the documents that have been added to our database:

GET /rest/baeldung HTTP/1.1
Authorization: Basic YWRtaW46TmV3UGFzc3dvcmQ=
---
HTTP/1.1 200 OK
Content-Type: application/xml; charset=UTF-8
<database xmlns="http://basex.org/rest" name="baeldung"> <resource type="xml" content-type="application/xml" size="104627">factbook.xml</resource> <resource type="xml" content-type="application/xml" size="5256">other.xml</resource> <resource type="xml" content-type="application/xml" size="5256">xmark.xml</resource> </database>

We can then access these resources directly by including them on the URL too – for example, /rest/baeldung/other.xml:

GET /rest/baeldung/other.xml HTTP/1.1
Authorization: Basic YWRtaW46TmV3UGFzc3dvcmQ=
---
HTTP/1.1 200 OK
Content-Type: application/xml; charset=UTF-8
<?xml version="1.0"?>
<site>
  <regions>
    <africa>
...
    </closed_auction>
  </closed_auctions>
</site>

5.5. Querying Resources

In addition to simply retrieving the entire resources that we’ve added to our database, we can execute queries against them to get back the data that we’re interested in.

We can do simple queries using the query parameter on our URL. We can do this either on a single resource or on the database as a whole:

GET /rest/baeldung?query=//item/name HTTP/1.1
Authorization: Basic YWRtaW46TmV3UGFzc3dvcmQ=
---
HTTP/1.1 200 OK
<name>duteous nine eighteen </name>
<name>great </name>
...
<name>practice space commune women </name>
<name>holds perhaps despair amorous </name>

Note that, in this case, we get back exactly the same as if we ran the query in the command-line client. This means it’s not a single XML document, but rather a stream of outputs from our query – in this case, a set of XML elements matching our query.

We can also provide more complicated XQuery queries as an HTTP POST call:

POST /rest/baeldung HTTP/1.1
Authorization: Basic YWRtaW46TmV3UGFzc3dvcmQ=
Content-Type: application/xml
<query xmlns="http://basex.org/rest">
  <text><![CDATA[ for $i in (//city/name)[position() <= 5] return string-length($i) ]]></text>
</query>
---
HTTP/1.1 200 OK
6
7
6
5
7

This query will return the lengths of the first five entries in the XPath //city/name, executed across the entire database. As before, this isn’t a single XML document but rather a stream of the values returned by our query.

5.6. Manipulating Resources

In addition to querying our resources, we’re also able to create and update them. We can do this with the PUT method to the desired resource, sending the entire XML resource as the request body:

PUT /rest/baeldung/new.xml HTTP/1.1
Authorization: Basic YWRtaW46VGhlUGFzc3dvcmQ=
Content-Type: application/xml
<?xml version="1.0" standalone="yes"?>
<site>
  <regions>
    <africa>
...
    </closed_auction>
  </closed_auctions>
</site>

If this resource already exists within the database, we’ll replace it. If it doesn’t already exist, we’ll create a new one instead.

We can delete resources in the same way, using the DELETE method on the resource:

DELETE /rest/baeldung/new.xml HTTP/1.1
Authorization: Basic YWRtaW46VGhlUGFzc3dvcmQ=

Once done, these changes are immediately available to query as with any other data in our database.

6. Summary

In this article, we’ve taken a very quick look at the BaseX database system. There’s a lot more that we can do with this system. Next time you need to query and manipulate large amounts of XML data for your applications, why not give it a try?

The post Introduction to BaseX first appeared on Baeldung.
       

 

Content mobilized by FeedBlitz RSS Services, the premium FeedBurner alternative.