Schema experiences

Any XML document must conform to a set of rules: the schema. While we hide as much of the technical implications and complexities from the author – it’s our most important design principle – we can never go as far as to pretend these don’t exist at all. One way or another, our users are authoring XML documents which requires them to adhere to the schema.

The rules of the schema are specified by files according to a well-known specification. At this time, FontoXML supports schemas defined in accordance with the XML Schema specification, usually provided as XSD files. These schema files need to be pre-processed and combined by our schema compiler for use in your FontoXML application. The result of this is a .json file that can be loaded and used for validation by FontoXML.

While the schema file describes the ways in which the elements of your documents may be combined, it does not specify the appearance they should take on in your documents and the behavior they should demonstrate when users interact with them in the editor. FontoXML will need to be configured to provide this information. Grouped together with the schema rules, we refer to this configuration as a Schema Experience.

In DITA applications, the term shell is often used to refer to a configuration of XSD files composing a schema. We adopt this term to be synonymous to schema experience, especially referring to the package that defines the root of the schema experience.

It is important to note that a schema experience only affects schema-dependent configuration in a FontoXML application. Such configuration should always be specified in a configureSxModule.js file, as this is the only place where a package has access to the SxModule defined for it. Please refer to Configure elements  for details on how to specify this configuration. Other configuration, such as any operations defined or configuration specified in your packages' install.js files, is global to the application and shared by all schema experiences.

Schema validation is applied automatically for all operations. Operations that apply to a schema other than the one used in the current document will be disabled automatically, as the result created is not valid for the current schema.

Schema experience modules

We recommend structuring a schema as a set of separate packages. For each schema used by your application, one package should hold the compiled .json file with the rules for the schema. Separate packages may each define the configuration for specific subsets of elements used in your schema. As these packages form the building blocks that together form the schema experience, we refer to these as schema experience modules. Separating configuration in this way is especially useful if such subsets are used by more than one schema in your application, which is usually the case with schemas built using a modular approach such as DITA.

FontoXML uses package dependencies to determine the configuration belonging to each schema experience in your application. By adding dependencies from the shell package to the schema experience modules containing the configuration, these configuration rules are combined automatically when the schema is used. In cases where multiple rules apply, FontoXML uses the value of the priority option from your configuration, the complexity of the XPath test (see "Selector specificity" in XPath) or the order of declaration to determine which configuration to use.

Some packages apply to all schema experiences in an application. We refer to these packages as add-ons. If you create a package containing a configureSxModule.js that should be used as an add-on, call sxModule.markAsAddon(). This will ensure that any rules defined for the package or its dependencies are included automatically in any schema experience created in the application.

The schema experience resolver

When a document is loaded, FontoXML uses a schema experience resolver to determine the schema experience to use. This allows a single FontoXML application to use multiple schema experiences depending on the content being loaded, and even allows doing so at the same time by loading multiple documents simultaneously. Depending on their requirements, applications should select a schema experience resolver from the following two options:

  • The SingleSchemaExperienceResolver can be used if your application always uses the same schema experience.
  • If your application uses multiple schema experiences, use the SchemaLocationToSchemaExperienceResolver. This resolver allows associating each schema experience with one or more locations. For any document loaded, the appropriate schema experience is determined by matching these locations against the value of the xsi:noNamespaceSchemaLocation, xsi:schemaLocations or doctype publicId or systemId, as appropriate for the document.

The schema locations associated with a schema may be listed in the fonto.json file included with the schema. Doing this will automatically generate a SCHEMA_LOCATIONS.js file in each schema experience package created when creating and FontoXML editor instance or compiling a schema, which can be used when integrating these schemas in your application (see below).

Integrating your schema(s)

To select the schema experience resolver and define the schemas used by your application, open the schemaExperienceResolver.js file in your application's config directory. Import the schema experience resolver you want to use and use the configuration manager to set the schema-experience-resolver configuration value to an instance of it from this file

The sxManager.defineSchemaExperience method should be used to create the definition for each schema experience passed to the resolver. This method expects the path to the schema .json file, starting with "assets/", as well as a list of packages that will, together with their dependencies, provide the configuration for this schema experience. The schema .json file may be placed in the assets directory for any package in your application (including config/assets), as the asset directories for all packages are merged. However, by convention the .json file will be placed in a single dedicated package representing the schema experience. By the same convention, any schema experience modules for the schema experience are listed as dependencies for that package rather than being mentioned in the schemaExperienceResolver.js file, and the array of package names passed to defineSchemaExperience only contains the name of this dedicated package.

For single schema applications, this file will look as follows:

config/schemaExperienceResolver.js
import configurationManager from 'fontoxml-configuration/src/configurationManager.js';
import sxManager from 'fontoxml-modular-schema-experience/src/sxManager.js';
import SingleSchemaExperienceResolver from 'fontoxml-schema-experience-resolver/src/SingleSchemaExperienceResolver.js';

configurationManager.set(
    'schema-experience-resolver',
    new SingleSchemaExperienceResolver(
        sxManager.defineSchemaExperience('assets/schemas/schema.json', ['my-schema-experience'])
    )
);

For applications using multiple schemas, each schema experience will be defined and registered with the resolver in turn, resulting in something like the following example:

config/schemaExperienceResolver.js
import configurationManager from 'fontoxml-configuration/src/configurationManager.js';
import sxManager from 'fontoxml-modular-schema-experience/src/sxManager.js';
import SchemaLocationToSchemaExperienceResolver from 'fontoxml-schema-experience-resolver/src/SchemaLocationToSchemaExperienceResolver.js';

// Schema experiences (DITA shells)
import MAPS_SCHEMA_LOCATIONS from 'my-dita-sx-shells-maps/src/SCHEMA_LOCATIONS.js';
import TOPICS_SCHEMA_LOCATIONS from 'my-dita-sx-shells-topics/src/SCHEMA_LOCATIONS.js';

var schemaLocationToSchemaExperienceResolver = new SchemaLocationToSchemaExperienceResolver();

schemaLocationToSchemaExperienceResolver.register(
    sxManager.defineSchemaExperience('assets/schemas/my-dita-sx-shells-maps.json', [
        'my-dita-sx-shells-maps'
    ]),
    MAPS_SCHEMA_LOCATIONS
);

schemaLocationToSchemaExperienceResolver.register(
    sxManager.defineSchemaExperience('assets/schemas/my-dita-sx-shells-topics.json', [
        'my-dita-sx-shells-topics'
    ]),
    TOPICS_SCHEMA_LOCATIONS
);

configurationManager.set('schema-experience-resolver', schemaLocationToSchemaExperienceResolver);