Fonto Editor specific examples

This page contains a list of XPath and XQuery examples that use functions that are unique to Fonto Editor. These examples can therefore not be run in the playground and can not be used in other applications or programming languages that support XPath or XQuery.

Text content

Sometimes you need the text content of a given node or range. Getting the text content of a given node is fairly simple. You could write something like the following example.

Text contents



Open example in playground

However, you will encounter one problem when using this solution. It will not take schema configuration into account. It will happily return the text contents of all descendants of a given node.

The platform provides two XQuery functions called curated-text-in-node and curated-text-in-range to solve this problem. These functions do take schema configuration into account.

The BlueprintQuery.getTextContent function is often used to get the text content of a node. This function is deprecated and it has the same problem as described above. The curated-text-in-node and curated-text-in-range should be used instead.

How do they work?

These functions return the curated text. Any text under detached (e.g. footnotes) and removed nodes will not be returned. Newline characters will be inserted in places where a boundary from inline context to block context is crossed. This happens, for example, when crossing the border of an element configured as block. Newline characters will also be inserted when a break element is encountered.

Result without newlines

You can remove the inserted newlines afterwards if you don't want them in the resulting string. You can use the normalize-space function for this. This function replaces leading and trailing whitespace from a given string. It replaces sequences of whitespace characters with a single space character.

Example with normalize-space


import module namespace fonto = ""; fonto:curated-text-in-node(.) => normalize-space()

Runnable example of the normalize-space function


normalize-space("   123 
 456   ")

Open example in playground

Usage examples

You have to include the module import before you can use this function. Refer to the examples below to see how to do this.

You can use javascript template literals when adding the module import. This allows you to use newlines in your queries. Refer to the examples below to see how to do this.

The curated-text-in-range function can be used in places where the text content of the current selection needs to be obtained.

Usage example in add-on using evaluateXPath


import evaluateXPath from 'fontoxml-selectors/src/evaluateXPath.js';
import evaluateXPathToString from 'fontoxml-selectors/src/evaluateXPathToString.js';
import readOnlyBlueprint from 'fontoxml-blueprints/src/readOnlyBlueprint.js';
import selectionManager from 'fontoxml-selection/src/selectionManager.js';

function textFromSelection () {
	return evaluateXPathToString(
		`import module namespace fonto = "";
		fonto:curated-text-in-range($startContainer, $startOffset, $endContainer, $endOffset)`,
		null, // We don't use the context node
			startContainer: selectionManager.getStartContainer(),
			startOffset: selectionManager.getStartOffset(),
			endContainer: selectionManager.getEndContainer(),
			endOffset: selectionManager.getEndOffset()

An alternative version of the example above. Here we use the useXPath React hook to update the UI whenever the selection in the document changes. Please refer to the guides on creating a sidebar and creating a modal for more information on how you can use this code in the UI. Refer to the FDS concept page for more information on FDS.

Usage example in add-on using useXPath


function SelectedText({ selection }) {
    const selectedText = useXPath(`
        import module namespace fonto = "";
		fonto:curated-text-in-range($startContainer, $startOffset, $endContainer, $endOffset)`,
        { variables: selection });
    return <Text>{selectedText}</Text>;

function useSelection() {
    const [selection, setSelection] = useState(null);
    useEffect(() => {
        return selectionManager.selectionChangeNotifier.addCallback(() => {
            setSelection(selectionManager.hasSelection() ? {
                startContainer: selectionManager.getStartContainer(),
                startOffset selectionManager.getStartOffset(),
                endContainer: selectionManager.getEndContainer(),
                endOffset selectionManager.getEndOffset()
            } : null);
    return selection;

function Selection() {
    const selection = useSelection();
    // There may not always be a selection, use something like the following to prevent invoking the XPath function with invalid arguments
    return selection ? <SelectedText selection={selection} /> : <Text>(no selection)</Text>;

The curated-text-in-node function can also be used in title queries. You don't want the contents of elements like footnotes to be included in the resulting title. Please be aware that calling this function will fail if the argument is not exactly a single node. When using a path or other expression that may result in zero or multiple nodes, consider using an expression such as shown in the following example to avoid errors:

Usage example in element configuration


configureAsSheetFrame(sxModule, 'self::topic', 'topic', {
	titleQuery: `import module namespace fonto = "";
	string-join(./title ! fonto:curated-text-in-node(.))`