<commit_before>This document describes the mapping between XML Schema components and Python
constructs as used in the default generation module.

Pythonic XML
============

How XML concepts should be represented in Python is a matter of taste.  For
a complex type, I expect to see its member elements as class members.  I
also expect attributes as class members.  As noted in Namespace Issues
below, this can create ambiguities and errors since XML views these as
different namespaces.

Personal Python style also comes into play: some might want member variables
to be inspected and mutated only through accessor methods.  The generation
infrastructure permits you to customize this through the assignment of an
InterfaceGenerator instance.  This generator defines the mapping from the
XML name to the internal class variable name, and provides an opportunity to
define inspector and mutator methods.

name : component -> python identifier
inspect : component -> python identifier or method invocation
mutate : component + python expression -> python statement

Namespace Issues
================

In XML schema, the namespaces for element declarations, type definitions,
and attribute definitions are all distinct.  Python uses the same namespace
for everything.  So, if you have a schema that defines a simple type
"color", you can then have an element named "color" that has an attribute
"color" with type "color".  Since the natural representation of elements
inside complex types is also by their schema name, the chances of conflict
are high.

Representation of Schema Components
===================================

Attribute Declaration
---------------------

Attribute declarations are simply a binding of a name to a type.  They are
not themselves represented, but provide the name for an Attribute Use.

Attribute Use
-------------

An attribute use is represented as an instance variable with accessor
methods in the class used for its owning CTD.  Each class that allows
attributes contains a class variable _AttributeUses which is a list of
instances that provide the name, Python class, and use restrictions for each
attribute.  In the case of classes defined by restriction, the variable
corresponding to the accessor remains in the parent class, but a new
instance is added to the local _AttributeUses list, and new accessors may be
defined to implement an updated use property.

class _AttributeUse:
  name = ncName
  pythonClass = SimpleTypeDefinitionClass (None for inherited uses)
  inheritedUse = _AttributeUse (parent class use reference)
  use = USE_prohibited | USE_required (0 = USE_optional)

Attribute Groups
----------------

An attribute group is represented as a mix-in class that contains a set of
one or more attribute uses, structured in the same way as for
element-content complex type definitions.  The mix-in class inherits from
PyWXSB.binding._AG_mixin.

Simple Type Definitions
-----------------------

(The material in this section applies both to SimpleTypeDefinitions and to
ComplexTypeDefinitions with simple content.)

STDs are represented by classes.  Classes are associated with facet
instances.  The classes themselves are either valueless or descend from a
Python built-in type.

Local STDs are assigned a protected-scope name that is unique within their
namespace.

Primitive STDs are the ones in the XMLSchema datatypes list, and are
built-in to PyWXSB.  The structure of a primitive STDs depends on its
variety.

Any facets defined for the given STD are created as class variables using a
name template [option].  The STD also contains a private class variable
__FacetMap which maps from facet classes to instances of that class.  A type
has an entry in the map for a facet class only if the facet is legal to
apply to that type.  Maps for subclasses are copies of the superclass map,
with additional constraints overwriting the parent ones.

Enumeration facets will add class variables corresponding to each
enumeration value.  [option] If a prefix is associated with the enumeration,
the enumeration value will also be promoted to the module (namespace) level,
using the prefix.  Both these options are configurable at the namespace and
named STD levels.

The constructor for an STD will check the resulting value against the
constraints that apply to that STD.  THis may be inconvenient in some cases;
for example, a subtype of NMTOKENS that requires a length of 5 must be
created with an iterable holding five elements; it cannot be built up
piece-by-piece.

Atomic STDs
~~~~~~~~~~~

Atomic simple type definitions inherit from the base type definition, which
is assumed to already have a Python type associated with it from its
primitive type.

List STDs
~~~~~~~~~

A list STD inherits from the datatypes._PST_list class, which combines
_PST_mixin with Python's list type and adds other stuff.  The class
associated with the item type is stored in a class variable _ItemType.

A BadTypeValue is raised when a list STD's constraints are checked and a
member of the list is not an instance of the _ItemType.

Union STDs
~~~~~~~~~~

A union STD does not have data associated with it; rather, it is a class
used to disambiguate the desired member type upon creation from an XML
string.  It inherits from _PST_union only.  Subclasses must include a
variable _MemberTypes which is a tuple of non-union STD classes, in the
order defined by the schema.

The class includes a public Factory class method which converts a string
into the appropriate instance of a member type, by attempting to create a
validated member instance of each member type in turn.

@todo Unions can be constrained by pattern or enumeration facets.

Enumerations
~~~~~~~~~~~~

A key purpose of PyWXSB is to support named constants to represent
enumeration values.  An STD has a class member variable _CF_enumeration if
it has an enumeration restriction.  Any such class should also mix-in the
facets._Enumeration_mixin class, to help with conversion between Unicode
values and the enumeration constant values.

The _CF_enumeration variable is an instance of the facets.CF_enumeration
class.  Each class maintains a set of facets._EnumerationElement instances
which record enumeration values.  Note that because the instance includes a
reference to the class that owns the facet, the definition of the instance
has to follow the class proper.

Complex Type Definitions
------------------------

Complex type definitions are represented by Python classes.  The _CTD_mixin
is a base class for all CTDs.

Each CTD includes a class variable _Particle which is None for empty and
simple content, and is an instance of binding._Particle for element and
mixed content.

The base _CTD_mixin class provides an XsdCreateFromDOM method that walks the
class hierarchy to assign attribute values, and the _Particle hierarchy to
extract element values.

CTDs that are defined by extension apply thusly:
* Any attribute or element that matches a corresponding attribute or element
  in the base class is inherited from the base class.
* New attributes and elements are introduced locally.

CTDs that are defined by restriction apply thusly:
* Any attribute or element that appears in the base type is inherited from
  the parent class, but retains a local constraint corresponding to the use
  and occurrence<commit_msg>Update enumeration description<commit_after>This document describes the mapping between XML Schema components and Python
constructs as used in the default generation module.

Pythonic XML
============

How XML concepts should be represented in Python is a matter of taste.  For
a complex type, I expect to see its member elements as class members.  I
also expect attributes as class members.  As noted in Namespace Issues
below, this can create ambiguities and errors since XML views these as
different namespaces.

Personal Python style also comes into play: some might want member variables
to be inspected and mutated only through accessor methods.  The generation
infrastructure permits you to customize this through the assignment of an
InterfaceGenerator instance.  This generator defines the mapping from the
XML name to the internal class variable name, and provides an opportunity to
define inspector and mutator methods.

name : component -> python identifier
inspect : component -> python identifier or method invocation
mutate : component + python expression -> python statement

Namespace Issues
================

In XML schema, the namespaces for element declarations, type definitions,
and attribute definitions are all distinct.  Python uses the same namespace
for everything.  So, if you have a schema that defines a simple type
"color", you can then have an element named "color" that has an attribute
"color" with type "color".  Since the natural representation of elements
inside complex types is also by their schema name, the chances of conflict
are high.

Representation of Schema Components
===================================

Attribute Declaration
---------------------

Attribute declarations are simply a binding of a name to a type.  They are
not themselves represented, but provide the name for an Attribute Use.

Attribute Use
-------------

An attribute use is represented as an instance variable with accessor
methods in the class used for its owning CTD.  Each class that allows
attributes contains a class variable _AttributeUses which is a list of
instances that provide the name, Python class, and use restrictions for each
attribute.  In the case of classes defined by restriction, the variable
corresponding to the accessor remains in the parent class, but a new
instance is added to the local _AttributeUses list, and new accessors may be
defined to implement an updated use property.

class _AttributeUse:
  name = ncName
  pythonClass = SimpleTypeDefinitionClass (None for inherited uses)
  inheritedUse = _AttributeUse (parent class use reference)
  use = USE_prohibited | USE_required (0 = USE_optional)

Attribute Groups
----------------

An attribute group is represented as a mix-in class that contains a set of
one or more attribute uses, structured in the same way as for
element-content complex type definitions.  The mix-in class inherits from
PyWXSB.binding._AG_mixin.

Simple Type Definitions
-----------------------

(The material in this section applies both to SimpleTypeDefinitions and to
ComplexTypeDefinitions with simple content.)

STDs are represented by classes.  Classes are associated with facet
instances.  The classes themselves are either valueless or descend from a
Python built-in type.

Local STDs are assigned a protected-scope name that is unique within their
namespace.

Primitive STDs are the ones in the XMLSchema datatypes list, and are
built-in to PyWXSB.  The structure of a primitive STDs depends on its
variety.

Any facets defined for the given STD are created as class variables using a
name template [option].  The STD also contains a private class variable
__FacetMap which maps from facet classes to instances of that class.  A type
has an entry in the map for a facet class only if the facet is legal to
apply to that type.  Maps for subclasses are copies of the superclass map,
with additional constraints overwriting the parent ones.

Enumeration facets will add class variables corresponding to each
enumeration value.  [option] If a prefix is associated with the enumeration,
the enumeration value will also be promoted to the module (namespace) level,
using the prefix.  Both these options are configurable at the namespace and
named STD levels.

The constructor for an STD will check the resulting value against the
constraints that apply to that STD.  THis may be inconvenient in some cases;
for example, a subtype of NMTOKENS that requires a length of 5 must be
created with an iterable holding five elements; it cannot be built up
piece-by-piece.

Atomic STDs
~~~~~~~~~~~

Atomic simple type definitions inherit from the base type definition, which
is assumed to already have a Python type associated with it from its
primitive type.

List STDs
~~~~~~~~~

A list STD inherits from the datatypes._PST_list class, which combines
_PST_mixin with Python's list type and adds other stuff.  The class
associated with the item type is stored in a class variable _ItemType.

A BadTypeValue is raised when a list STD's constraints are checked and a
member of the list is not an instance of the _ItemType.

Union STDs
~~~~~~~~~~

A union STD does not have data associated with it; rather, it is a class
used to disambiguate the desired member type upon creation from an XML
string.  It inherits from _PST_union only.  Subclasses must include a
variable _MemberTypes which is a tuple of non-union STD classes, in the
order defined by the schema.

The class includes a public Factory class method which converts a string
into the appropriate instance of a member type, by attempting to create a
validated member instance of each member type in turn.

@todo Unions can be constrained by pattern or enumeration facets.

Enumerations
~~~~~~~~~~~~

A key purpose of PyWXSB is to support named constants to represent
enumeration values.  An STD has a class member variable _CF_enumeration if
it has an enumeration restriction.  This variable supports translation
between tag, value, and unicode representations of the enumeration.

The _CF_enumeration variable is an instance of the facets.CF_enumeration
class.  Each instance maintains a set of facets._EnumerationElement
instances which record enumeration values.  Note that because the instance
includes a reference to the class that owns the facet, the definition of the
instance has to follow the class proper.

Complex Type Definitions
------------------------

Complex type definitions are represented by Python classes.  The _CTD_mixin
is a base class for all CTDs.

Each CTD includes a class variable _Particle which is None for empty and
simple content, and is an instance of binding._Particle for element and
mixed content.

The base _CTD_mixin class provides an XsdCreateFromDOM method that walks the
class hierarchy to assign attribute values, and the _Particle hierarchy to
extract element values.

CTDs that are defined by extension apply thusly:
* Any attribute or element that matches a corresponding attribute or element
  in the base class is inherited from the base class.
* New attributes and elements are introduced locally.

CTDs that are defined by restriction apply thusly:
* Any attribute or element that appears in the base type is inherited from
  the parent class, but retains a local constraint corresponding to the use
  and occurrence
{'fraction_non_alphanumeric': 0.04917920656634747, 'fraction_numerical': 0.00027359781121751026, 'mean_word_length': 4.341980270369017, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7275553', 'n_tokens_mistral': 3476, 'n_tokens_neox': 3340, 'n_words': 2173}