FontoXPath

repository·master·Indexed 41 days ago

https://github.com/fontoxml/fontoxpath

A minimalistic XPath 3.1 and XQuery 3.1 engine for JavaScript designed for querying XML nodes. It features support for the XQuery Update Facility 3.0, a profiler API, and the ability to compile a subset of XPath 3.1 into pure JavaScript for high performance. The engine is DOM-agnostic and includes a type inference system to optimize evaluation via AST annotation.

Tokens
7.4K
Snippets
20
Records
37
Agent score
100%

What's inside FontoXPath

  1. How type inference and annotation work in FontoXPath

    master

    FontoXPath uses a type inference system to annotate the Abstract Syntax Tree (AST) of XPath or XQuery scripts. This process, triggered by the annotateAST function, performs a depth-first, pre-order traversal to determine the type of each node and inserts a SequenceType into the AST as an attribute named type.

    Key Mechanisms

    • Function Resolution: Function references are resolved by extracting the QName and performing a lookup in the StaticContext to determine arity, name, and return type.
    • Variable Resolution: The AnnotationContext manages variable scopes (pushing and popping scopes during flwor expressions) to track variable types.
    • Namespace Resolution: Prefixes are resolved using the namespaceResolver and defaultFunctionNamespaceURI provided during evaluateXPath or parseScript, as well as namespaces defined in the XQuery prolog.

    Indeterminate Types

    If a type cannot be determined during annotation (e.g., due to runtime dependency or unsupported functions), the node is annotated with the fallback item()* type: { type: ValueType.ITEM, mult: SequenceMultiplicity.ZERO_OR_MORE }.

    Nodes that always receive this fallback include:

    • ContextItemExpr
    • DynamicFunctionInvocationExpr
    • UnaryLookup
  2. Understand FontoXPath compatibility and limitations

    master

    FontoXPath is an XPath engine with the following specification characteristics:

    • XPath Version: It assumes XPath 1.0 compatibility mode is turned off.
    • XPath 3.1 Support: Not all XPath 3.1 functions are implemented. You can check supported functions via the FontoXPath Playground by selecting the 'Report on which functions are implemented' example.
    • Unavailable Features: Currently, the following are not supported:
      • Some DateTime related functions
      • Collation related functions (fn:compare#3)
      • XML parsing
      • The treat as operator
      • Some parts of FLWOR expressions
    • DOM Compatibility: The engine is DOM-agnostic and works well with browser DOM implementations and slimdom.js.
      • Warning: Avoid using xmldom due to namespace implementation issues.
      • Warning: Avoid using the HTML DOM when working with namespaces, as it may not behave as expected.
  3. How type annotation optimizes XPath evaluation

    master

    The annotation process improves evaluation efficiency through Early Returns.

    When types are known via annotation, FontoXPath can skip expensive runtime type checks. For example, binary and unary operators can skip type checking if the operand types are already known. If the annotated type is more general than what the operator requires, the system performs type narrowing; otherwise, it falls back to original dynamic type inference.

    Currently optimized aspects include:

    • Binary Operator
    • Unary Operator
    • Value Compare
    • General Compare
    • Node Compare
  4. Compile XPath to JavaScript for high performance

    master

    For performance-critical applications, you can compile a subset of XPath 3.1 into pure JavaScript. This can be 2 to 7 times faster than standard evaluation.

    Workflow:

    1. Use compileXPathToJavaScript to generate a compiled object.
    2. Check if isAstAccepted is true (not all XPaths are supported for JS codegen).
    3. If accepted, create a function using new Function(compiledResult.code).
    4. Execute the function using executeJavaScriptCompiledXPath.
    import { compileXPathToJavaScript, executeJavaScriptCompiledXPath } from 'fontoxpath';
    
    const compiledXPathResult = compileXPathToJavaScript('/child::p/text()', evaluateXPath.BOOLEAN_TYPE);
    
    if (compiledXPathResult.isAstAccepted) {
    	const evalFunction = new Function(compiledXPathResult.code) as CompiledXPathFunction;
    	const result = executeJavaScriptCompiledXPath(evalFunction, documentNode);
    }
  5. Profile XPath performance

    master

    FontoXPath provides a profiler API to monitor the execution speed of your queries.

    1. Provide a performance implementation (e.g., window.performance).
    2. Start profiling with profiler.startProfiling().
    3. Retrieve a summary using profiler.getPerformanceSummary(), which returns an array of XPaths with their execution times and runtimes.
    import { profiler } from 'fontoxpath';
    
    profiler.setPerformanceImplementation(window.performance);
    profiler.startProfiling();
    
    const summary = profiler.getPerformanceSummary();
  6. Debug XPath expressions

    master

    To see a trace of where an XPath evaluation failed, set the debug: true option in the options object. This provides a line-by-line trace of the error location in the expression. Additionally, you can use the fn:trace function within your XPath/XQuery to output information to the developer console.

    evaluateXPathToBoolean('...', null, null, null, { debug: true });
  7. Create typed values for XPath variables

    master

    When passing JavaScript values as variables to an XPath expression, you can use createTypedValueFactory to ensure they are treated as specific XDM types (like xs:integer). Without this, plain JavaScript numbers are automatically converted to xs:double, which might cause type-check failures in your XPath (e.g., instance of xs:integer would return false).

    const integerValueFactory = createTypedValueFactory('xs:integer');
    const integerValue = integerValueFactory(123, domFacade);
    
    evaluateXPathToBoolean('$value instance of xs:integer', null, null, {
    	value: integerValue,
    });
  8. Enable annotation in qt3 tests

    master

    To test the type inference system using the qt3 test suite, run the tests with the --annotate flag. This ensures all XPath queries undergo the annotation step at the start of execution.

    # Example command to run tests with annotation enabled
    # (Note: exact command depends on your local test runner setup)
    # The flag to pass to the test suite is:
    --annotate
  9. What is an EvaluableExpression?

    master

    An EvaluableExpression is the input selector for evaluateXPath. It can be one of two types:

    1. A string: A standard XPath or XQuery expression (e.g., //item/text()).
    2. An Element: An element representing the root of an XQueryX DOM tree. These can be created manually or via a parseScript function.
  10. Debug unannotated queries using logUnannotatedQueries

    master

    You can identify queries that failed to be fully annotated by enabling the logUnannotatedQueries flag in the Options object.

    When enabled, FontoXPath checks if a query was completely annotated at the end of its execution. If not, it logs the query to console.error. You can capture these errors by redirecting stderr to a file.

    Example command to capture unannotated query logs:

    npm run test 2> output.txt
  11. Modify XML using XQuery Update Facility (XQUF)

    master

    To perform updates (insert, replace, delete) on XML, use evaluateUpdatingExpressionSync.

    This function returns an object containing:

    • xdmValue: The result of the query.
    • pendingUpdateList: An array of update primitives.

    To apply these changes to your DOM, you must pass the pendingUpdateList to executePendingUpdateList.

    const { evaluateUpdatingExpressionSync, executePendingUpdateList } = require('fontoxpath');
    
    const result = evaluateUpdatingExpressionSync('replace node /xml with <foo/>', documentNode);
    executePendingUpdateList(result.pendingUpdateList, domFacade, nodesFactory, documentWriter);
  12. Query XML using evaluateXPath

    master

    The primary way to execute XPath or XQuery in FontoXPath is using the evaluateXPath function. It allows you to run queries against a DOM via an IDomFacade.

    Parameters:

    • xpathExpression (String): The query string.
    • contextNode (Node): The starting node (defaults to null).
    • domFacade (IDomFacade): The DOM implementation. Defaults to a standard DOM spec implementation.
    • variables (Object): A map of variables available in the global namespace of the expression.
    • returnType (number): Determines the result type. Use evaluateXPath.ALL_RESULTS_TYPE for predictable results. Other types include NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE, NODES_TYPE, FIRST_NODE_TYPE, STRINGS_TYPE, MAP_TYPE, ARRAY_TYPE, ASYNC_ITERATOR_TYPE, and NUMBERS_TYPE.
    • options (Object): Configuration for namespaces, language (XPath 3.1 or XQuery 3.1), module imports, and debugging.
    evaluateXPath(xpathExpression, contextNode, domFacade, variables, returnType, options);