Representing Schemas as XML
Importing Schema from XML Files
It would be useful to have a trivially paresable XML format for defining schemas, exposing the full expressiveness of the Zope3 schema model to non-programmers (both the CSV and HTML formats are subsests).
I would propose that we create a format based on an objectify-like representation of a set of schemas, e.g., something like:
>>> _SCHEMA_XML = """ ... <schemas> ... <schema name="myschema"> ... <field name="favorite_color" type="TextLine"> ... <title>Favorite Color</title> ... <description>What is your favorite color?</description> ... <required>True</required> ... <readonly>False</readonly> ... </field> ... <field name="favorite_number" type="Int"> ... <title>Favorite Number</title> ... <description>What is your favorite number?</description> ... <required>False</required> ... <readonly>False</readonly> ... </field> ... </schema> ... </schemas>"""
In order to generate a schema from this, we need to register utilities which can convert nodes with a given type into fields:
>>> from zope.component import provideUtility >>> from userschema.etree import INodeToField
We need one "node converter" for each kind of field. The etree module defines handlers for various "stock" field types:
>>> from userschema.etree import TextLineHandler >>> from userschema.etree import IntHandler >>> provideUtility(TextLineHandler, INodeToField, 'TextLine') >>> provideUtility(IntHandler, INodeToField, 'Int')
We can then create a schema from the XML document:
>>> from zope.interface.interface import InterfaceClass >>> from zope.schema import TextLine >>> from userschema.etree import fromXML >>> a_schema = fromXML(_SCHEMA_XML) >>> type(a_schema) is InterfaceClass True
If we don't override it, the __name__ of the generated interface is derived from the schema element's name attribute:
>>> print a_schema.__name__ myschema
We can pass the 'element_name' to override:
>>> a_schema = fromXML(_SCHEMA_XML, name='foobar') >>> print a_schema.__name__ foobar
The '__module__' attribute of the generated interface defaults to 'userschema':
>>> print a_schema.__module__ userschema
We can override that by passing 'module_name':
>>> a_schema = fromXML(_SCHEMA_XML, module_name='somemodule') >>> print a_schema.__module__ somemodule
The attributes of the schema correspond to the form widget names:
>>> names = list(a_schema.names()) >>> names.sort() >>> print names ['favorite_color', 'favorite_number']
Configuring this Stuff
We would then add a ZCML directive, e.g.:
<userschema:xmldefinition target="dotted.path" <!-- optional override --> package="dotted.path" <!-- for relative filenames --> file="filename.xml" schema="myschema" />
We might even get fance, and allow pulling out only some fields:
<userschema:xmldefinition target="dotted.path" <!-- not optional for field subsets --> package="dotted.path" <!-- for relative filenames --> file="filename.xml" fields="//schema[@id=myschema]/...." <!-- XPath yielding field nodes --> />
Or, for extra bonus points, we could combine field sets, e.g.:
<userschema:xmldefinition target="dotted.path"> <!-- required for this use case --> <userschema:xmlsubset package="dotted.path" file="filename.xml" schema="myschema" /> <userschema:xmlsubset package="Products.CMFCore" filename="dublincore.xml" schema="simple_dublin_core" /> </userschema:xmldefinition>
Note that, as with other forms of reuse, these last two options work against the goal of making non-programmers responsible for specifying schema definitions.
Emitting XML Representations of Schemas
We would likely need to be able to emit this XML format, too, which would make integrating forms based Zope3 schema into Paul's 'agility' work more straightforward.
cvs: $Id: etree-schema.txt,v 1.4 2007/01/31 17:52:36 tseaver Exp $: