How a schema parser works ========================= An object which implements the diISchemaParser interface is responsible to load a schema, to parse it, and to return a diIValidationSchema object. This diIValidationSchema object will be used to validate a document or an specific element in a document. How the relaxNG parser works ============================ the diRelaxNGParser object -------------------------- The "public" object of the parser is a diRelaxNGParser object, which implements the diISchemaParser interface. When its method ParseSchemaFromFile is called, it creates a diRelaxNGContentParser which implements the diIRelaxNGContentParser interface. the diRelaxNGContentParser object ---------------------------------- The diRelaxNGContentParser is the core of the RelaxNG parser, and implements also other interface like nsISAXContentHandler, nsISAXErrorHandler, diIRelaxNGGrammarPatternInfo. In fact, it is a sax parser, which parses a single relaxNG file. So if a relaxNG file refers to another relaxNG file, an other diRelaxNGContentParser will be created to parse this second relaxNG file. creating pattern builders ------------------------- When a diRelaxNGContentParser parse a file, it creates a pattern builder each time it finds a relaxng pattern. a pattern builder is an object which implements diIRelaxNGPatternBuilder, it exists a pattern builder for each pattern type in the relaxNG grammar. A pattern builder is then responsible to do things, depending of the pattern. Most of time, this thing is to create a pattern, an object which will serve to validate something in the document. patterns --------- Patterns created by pattern builders are objects which implement the diIRelaxNGPattern interface, Element and attribute patterns implement also two other interfaces : - one interface for the relaxNG extension : diIRelaxNGElementPatternInfo, diIRelaxNGAttributePatternInfo. It allows to setup some extra informations (label, description etc) - one interface for the validation part : diISchemaElement, diISchemaAttribute, from which we can get informations (at least) set with the *patternInfo interfaces. At the end of the parsing (after the call of the diRelaxNGParser::load method), we have a hierachy of patterns, stored in a diIRelaxNGRootGrammar object. generation of a diIValidationSchema object ------------------------------------------ When we call the diIRelaxNGRootGrammar::finalize() method, it does things to finalize the schema : - simplification - restriction checking All of this is done according to the RelaxNG specification. The resulting patterns and other informations are then stored in a new diRelaxNGSchema object, which implements a diIValidationSchema dans diIValidationSchemaQuery. This is this object which will be used for the validation. RelaxNG extensions ------------------ extension are components which allow the parser to support other elements than relaxNG elements. An extension is responsible to support elements which have a specific namespace. the components should implements the diIRelaxNGExtensionFactory. It is called each time an attribute or an element with the specific namespace is found. For each attribute, getAttributeHandler is called, and this method should return a diIRelaxNGExtension object. For each elements, getSubTreeListener is called, and this method should return a diIRelaxNGExtensionListener object. Then, all SAX events generated during the parsing of the subtree of the element, are propagated to this object. Note that the diIRelaxNGExtensionListener interface inherits from the diIRelaxNGExtension interface. diIRelaxNGExtension objects are attached to the relaxNG pattern on which they appears, and their diIRelaxNGExtension::processOnPattern method is called after the end of the parsing of the relaxNG element. It is the opportunity for the diIRelaxNGExtension object to give information to the relaxNg pattern, through the given diIRelaxNGPatternInfo interface. How the validator works ======================= When we call the ValidateDocument method of a diIValidationSchema object, the document is validated against the schema. If the validition fails, you have details about the error in the validationError property. There is a parameter to this method : prepareForEditing. It is a boolean which says if the given document should be "prepared" for the editing or not. Eg, the validator should attach on each DOM elements a diISchemaElement object, so the validator could validate only a subtree of the document. So, when prepareForEditing is true, during this first validation of the entire document, a diISchemaElement object corresponding to each DOM elements should be attached via the userData property of DOM3Element. This property should be called "di-schema-info". Informations provided by diISchemaElement are used by the editor. But to validate a subtree, you should use the diIValidationSchemaQuery interface of the diIValidationSchema object. The validator can get the diISchemaElement object of the element to validate, then query an other interface of this object to validate the element. This is how the relaxNG validator does. It gets the diIRelaxNGElement interface of the object stored in the "di-schema-info" user data of the element, then it can call the "Deriv" method to validate the element and its children. (The RelaxnNG validator used the algorithm described by James Clark : http://www.thaiopensource.com/relaxng/derivative.html)