Skip to content

Instantly share code, notes, and snippets.

@joewiz
Last active January 29, 2022 00:45
Show Gist options
  • Save joewiz/69e767a20d32a22ffa37da95d75457b7 to your computer and use it in GitHub Desktop.
Save joewiz/69e767a20d32a22ffa37da95d75457b7 to your computer and use it in GitHub Desktop.
Basic dynamic web pages, with XQuery and eXist

Basic dynamic web pages, with XQuery and eXist

This self-guided tutorial builds up from a simple "Hello, World!" exercise to a dynamic web page that responds to user input. It uses eXist-db and teaches the basic interface elements of the eXide XQuery IDE for developing XQuery-based applications in eXist.

eXist is a free, open source native XML database. It's a great tool for learning how to query, analyze, and transform your data. Among the various interfaces for working with eXist, one of the most convenient is eXide, a browser-based IDE (integrated development environment) for writing XQuery modules and developing XQuery-based applications on your own computer without installing any additional software. eXide comes pre-installed with eXist and has a number of useful features. We'll just cover the basics here. And once you have something you'd like to turn into a web page, eXist has a built-in web server, so you can develop full-fledged web applications by learning just a few additional functions and techniques. This tutorial leads you through basic steps to turn your query into a dynamic web page, with forms that users can enter data into and with the Bootstrap CSS library to make your pages look pretty.

Preparation

  1. Download and install eXist. This tutorial assumes the you are running the current release version, 3.6.0.
  2. Open eXide at http://localhost:8080/exist/apps/eXide
  3. Download this Gist as a .zip file by clicking on the Download ZIP button at the top of the Gist); we'll use the files mid-way through the tutorial.

Running basic queries in eXide

  1. Copy and paste the following query into the editor pane.

    xquery version "3.1";
    
    <p>Hello, World!</p>
  2. Submit the query to eXist by selecting the Eval button in eXide's toolbar.

  3. See the results.

  4. Repeat these steps for the following query, observing the change in the code.

    xquery version "3.1";
    
    let $addressee := "World"
    return
        <p>Hello, { $addressee }!</p>

Saving query modules into the database

Instead of running our queries in eXide, we can do so directly in the web browser. This turns our queries into a true web page. But to do so, we first need to save the query in the database so it has a URL that we can call from the browser.

  1. For the next query, after pasting it into eXide, save the query to the database by selecting the Save button.

    xquery version "3.1";
    
    import module namespace request = "http://exist-db.org/xquery/request";
    
    let $addressee := request:get-parameter("addressee", "World")
    return
        <p>Hello, { $addressee }!</p>
  2. In the Save Document As dialog, drill into /db/apps, select Create Collection (the folder icon in the toolbar) to create a my-app collection, and save your query into this collection as 03-get-parameter.xq.

Loading a saved query in the browser and interacting with it via URL parameter

  1. Click on the Run in new tab button (the arrow icon just beneath the editor pane) to run this query in a new browser tab. If you named your collection and module as instructed, the URL for the new browser tab will open to http://localhost:8080/exist/apps/my-app/03-get-parameter.xq.
  2. Add ?addressee=Joe to the end of the URL and hit the return key to submit the query with this new parameter. Try your own values.

Uploading multiple query modules

Instead of copying, pasting, and saving each query, we can upload these queries in batch. Knowing how to upload and set permissions on the stored queries will save time.

  1. On your desktop, open the .zip file containing this Gist's files (00 through 06).
  2. Back in eXide, open the DB Manager again via File > Manage.
  3. Drill into the /db/apps/my-app collection, select Upload Files (the cloud icon in the toolbar), and either drag-and-drop the files onto the target or select the Upload Files button to navigate to the files.
  4. Once the upload is complete, select the Done button, select all of the files, select the Properties button (a circular "i" icon), and select all 3 "execute" checkboxes to make the queries executable.
  5. Exit the DB Manager dialog.

Serializing query output as HTML

Until now the queries have all returned raw XML to the browser. Let's tell the browser to treat the results as HTML.

  1. Use the Directory tab to the left of the editor pane to drill down to /db/apps/my-app. Open query 4, and use the Run in new tab button to try the query in a new browser tab.
  2. Again, add an addressee parameter to the end of the URL.

Adding an HTML form

Open query 5 in the browser and try out the interactive form.

Adding Bootstrap CSS to your form

Run query 6 in the browser.

Conclusion

Congratulations! You've developed a simple XQuery into a dynamic, HTML form, and you've learned your way around the eXide IDE for developing XQuery applications with eXist. Here are some ideas for next steps:

  1. Add some more fields to your form.
  2. Add value="{$addressee}" to your <input> elements to place the user-submitted fields back in the form after the user submits the form.
  3. Refactor your code to move the HTML wrapping code into a function, local:wrap-html, which takes a paramter, $content and perhaps even a second parameter $title.
  4. Upload your own XML data to eXist, and adapt your code to query the data.

Do you prefer to work in a code editor like Atom? Install the existdb package for Atom to add XQuery syntax highlighting, code completion and validation, and integration with eXist to Atom. Or, if you prefer to work with oXygen XML Editor, you can add eXist-db to oXygen as an External Data Source and XQuery Validation Engine.

Interested in learning more about XQuery? Check out Learning XQuery, a list of great articles, blog posts, and books for learning XQuery.

Interested in learning more about eXist? Check out eXist's documentation. The "Learning XQuery" page also links to the O'Reilly book about eXist.

xquery version "3.1";
<p>Hello, World!</p>
xquery version "3.1";
let $addressee := "World"
return
<p>Hello, { $addressee }!</p>
xquery version "3.1";
import module namespace request = "http://exist-db.org/xquery/request";
let $addressee := request:get-parameter("addressee", "World")
return
<p>Hello, { $addressee }!</p>
xquery version "3.1";
declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
declare option output:method "html5";
declare option output:media-type "text/html";
import module namespace request = "http://exist-db.org/xquery/request";
let $addressee := request:get-parameter("addressee", "World")
return
<p>Hello, { $addressee }!</p>
xquery version "3.1";
declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
declare option output:method "html5";
declare option output:media-type "text/html";
import module namespace request = "http://exist-db.org/xquery/request";
let $addressee := request:get-parameter("addressee", "World")
return
<div>
<p>Hello, { $addressee }! Please enter your name.</p>
<form method="get">
<input type="text" name="addressee"/>
<button type="submit">Submit</button>
</form>
</div>
xquery version "3.1";
declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
declare option output:method "html5";
declare option output:media-type "text/html";
import module namespace request = "http://exist-db.org/xquery/request";
let $addressee := request:get-parameter("addressee", "World")
return
(: https://getbootstrap.com/docs/3.3/getting-started/ :)
<html>
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>Title</title>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"/>
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous"/>
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"/>
</head>
<body>
<div class="container">
<h1>Title</h1>
<p>Hello, { $addressee }! Please enter your name.</p>
<form method="get">
<input type="text" name="addressee" class="form-control"/>
<button type="submit" class="btn btn-default">Submit</button>
</form>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment