Markup Blitz is a parser generator implemented in Java. It takes a context-free grammar, generates a parser for it, and uses the parser to convert input into a parse tree, provided that the input conforms to the grammar.
The algorithms used are
It also uses concepts from REx Parser Generator.
Markup Blitz is an implementation of Invisible XML (ixml). Please see the ixml specification for details on grammar notation and parse-tree serialization.
Use JDK 17 or higher. For building Markup Blitz, clone this GitHub repository and go to the resulting directory:
git clone https://github.com/GuntherRademacher/markup-blitz.git
cd markup-blitz Then run this command, on Unix/Linux,
./gradlew clean jaror this one, on Windows
gradlew clean jarThis creates build/libs/markup-blitz.jar which serves the Markup Blitz API. It is also usable as an executable jar for standalone execution.
For running the tests, use this command on Unix/Linux,
./gradlew testor this one on Windows:
gradlew testMarkup Blitz comes with a few tests, but it also passes all of the more than 5000 tests in the Invisible XML community project ixml, included as a git submodule. To run the full test suite, make sure that the submodule is loaded before running the tests:
git submodule update --init --recursiveExecuting these tests takes a few minutes, however some of the performance tests are skipped by default, because they require significantly more time or memory. For running those as well, set property ALL_TESTS to true:
./gradlew test -PALL_TESTS=true(on Windows omit the leading ./). Note that this causes JVM arguments to be set for a heap size of 16GB and a stack size of 4MB. Execution may take about 10 minutes in this case.
The project can be imported into Eclipse as a Gradle project.
Markup Blitz is available on Maven Central with groupId de.bottlecaps and artifactId markup-blitz.
Markup Blitz can be run from command line to process some input according to an Invisible XML grammar:
Usage: java -jar markup-blitz.jar [<OPTION>...] [<GRAMMAR>] <INPUT>
Compile an Invisible XML grammar, and parse input with the resulting parser.
<GRAMMAR> the grammar (literal, file name or URL), in ixml notation or XML.
XML grammars are detected automatically. When omitted, the grammar
of ixml itself is used, so that the input is parsed as an ixml
grammar.
<INPUT> the input (literal, file name or URL).
<OPTION>:
--indent generate resulting xml with indentation.
--trace print parser trace.
--fail-on-error throw an exception instead of returning an error document.
--timing print timing information.
--verbose print intermediate results.
A literal grammar or input must be preceded by an exclamation point (!).
All inputs must be presented in UTF-8 encoding, and output is written in
UTF-8 as well. Resulting XML goes to standard output, all diagnostics go
to standard error.When the grammar is omitted, Markup Blitz uses its built-in grammar of ixml to parse the input as an ixml grammar, producing its XML representation.
BaseX uses Markup Blitz to implement fn:invisible-xml. It can be tested online on BXFiddle.
A parser is generated by passing an Invisible XML grammar as a string to the generate method of class de.bottlecaps.markup.Blitz. This returns an object of type de.bottlecaps.markup.blitz.Parser, which has a parse method accepting the input string as a parameter and returns the resulting XML as a string.
Generate a parser from an Invisible XML grammar in ixml notation.
public static Parser generate(String grammar, Option... blitzOptions) throws BlitzExceptionParameters:
String grammar: the Invisible XML grammar in ixml notationOption... blitzOptions: options for use at generation time and parsing time
Returns: Parser: the generated parser
Throws: BlitzException: if any error is detected while generating the parser
Generate a parser from an Invisible XML grammar in XML, passed as an InputStream.
public static Parser generateFromXml(InputStream xml, Option... blitzOptions) throws BlitzExceptionParameters:
InputStream xml: the Invisible XML grammar in XMLOption... blitzOptions: options for use at generation time and parsing time
Returns: Parser: the generated parser
Throws: BlitzException: if any error is detected while generating the parser
Generate a parser from an Invisible XML grammar in XML, passed as a String.
public static Parser generateFromXml(String xml, Option... blitzOptions) throws BlitzExceptionParameters:
String xml: the Invisible XML grammar in XMLOption... blitzOptions: options for use at generation time and parsing time
Returns: Parser: the generated parser
Throws: BlitzException: if any error is detected while generating the parser
Parse the given input, returning the resulting XML as a string.
public String parse(String input, Option... options)Parameters:
String input: the input stringOption options: options for use at parsing time. If absent, any options passed at generation time will be in effect
Returns: String: the resulting XML
Parse the given input, reporting the result to the given handler instead of returning a serialized XML string. This lets a caller build a result representation of its choice (for example a tree in a host language) directly from the parse tree, without an intervening serialized form.
public void parse(String input, ResultHandler resultHandler, Option... options)Parameters:
String input: the input stringResultHandler resultHandler: the handler that receives the parse resultOption options: options for use at parsing time. If absent, any options passed at generation time will be in effect
Parse the given input, returning the resulting XML as a string, while periodically calling the given checkpoint so that a long-running or non-terminating parse (for example one caused by an infinitely ambiguous grammar) can be aborted. The checkpoint may throw a RuntimeException to abort the parse; that exception propagates out of parse.
public String parse(String input, Runnable checkpoint, Option... options)Parameters:
String input: the input stringRunnable checkpoint: called periodically during parsing; it may throw aRuntimeExceptionto abort the parseOption options: options for use at parsing time. If absent, any options passed at generation time will be in effect
Returns: String: the resulting XML
Parse the given input, reporting the result to the given handler, while periodically calling the given checkpoint so that a long-running or non-terminating parse (for example one caused by an infinitely ambiguous grammar) can be aborted. The checkpoint may throw a RuntimeException to abort the parse; that exception propagates out of parse.
public void parse(String input, ResultHandler resultHandler, Runnable checkpoint, Option... options)Parameters:
String input: the input stringResultHandler resultHandler: the handler that receives the parse resultRunnable checkpoint: called periodically during parsing; it may throw aRuntimeExceptionto abort the parseOption options: options for use at parsing time. If absent, any options passed at generation time will be in effect
An implementation of ResultHandler receives the parse result as serialization-style callbacks, in document order. An element's attributes are reported by attribute, after the enclosing startElement and before any child content.
public interface ResultHandler {
/** Reports the start of an element. */
void startElement(String name);
/** Reports the end of an element. */
void endElement(String name);
/** Reports an attribute, with its value given as codepoints. */
void attribute(String name, int[] codepoints, int length);
/** Reports a run of codepoints of element content. */
void text(int[] codepoints, int length);
}Either of the generate and parse methods accepts Option arguments for creating extra diagnostic output. Generation time options are passed to the Parser object implicitly, and they are used at parsing time, when parse is called without any options.
/** Parser and generator options. */
public enum Option {
/** Parser option: Generate XML with indentation. */ INDENT,
/** Parser option: Print parser trace. */ TRACE,
/** Parser option: Fail on parsing error. */ FAIL_ON_ERROR,
/** Generator option: Print timing information. */ TIMING,
/** Generator option: Print information on intermediate results. */ VERBOSE;
}As with REx Parser Generator, the goal of Markup Blitz is to provide good performance. In general, however, REx parsers can be expected to perform much better. This is primarily because REx allows separating the specification into tokenization and parsing steps. This is in contrast to Invisible XML, which uses a uniform grammar to resolve from the start symbol down to codepoint level. Separate tokenization enables the use of algorithms optimized for this purpose, the establishment of token termination rules, and the easy accommodation of whitespace rules. Without it, all of this has to be accomplished by the parser alone, which often leads to costly handling of local ambiguities.
Some performance comparison of REx-generated parsers and Invisible XML parsers can be found in the rex-parser-benchmark project. This also covers a measurement of Markup Blitz performance.
Copyright (c) 2023-2026 Gunther Rademacher. Markup Blitz is provided under the Apache 2 License (see LICENSE.txt).
The work in this project was supported by the BaseX organization.