<spc:wrap xmlns="http://xmlns.livinglogic.de/xist/ns/doc" xmlns:spc="http://xmlns.livinglogic.de/xist/ns/specials">
<section><h>Converter contexts</h>

<p>Converter contexts can be used to pass around information in recursive
calls to the <meth>convert</meth> and <meth>mapped</meth> methods.
A <pyref module="ll.xist.xsc" class="Converter"><class>Converter</class></pyref>
object will be passed in all calls, so this object is the place to store
information. However if each element, procinst and entity class decided on its
own which attributes names to use, name collisions would be inevitable. To avoid
this, the following system is used.</p>

<p>When a class wants to store information in a converter, it has to define
a <class>Context</class> class (normally derived from the <class>Context</class>
class of its base class). The constructor must initialize the context object
to a initial state. You can get the context object for a certain class by treating
the converter as a dictionary with the class (or an instance) as the key like this:</p>

<example><h>Defining and using a converter context</h>
<prog>
from ll.xist import xsc

class counter(xsc.Element):
	class Context(xsc.Element.Context):
		def __init__(self):
			xsc.Element.Context.__init__(self)
			self.count = 0

	def convert(self, converter):
		context = converter[self]
		node = xsc.Text(context.count)
		context.count += 1
		return node
</prog>
</example>

</section>


<section><h>Chaining pools and extending namespaces</h>

<p>When using <pyref module="ll.xist.xsc" class="Pool">pools</pyref> it's
possible to do some sort of <z>namespace subclassing</z>.</p>

<p>Registering a module in a pool not only registers the element, procinst and
entity classes in the pool for parsing, but each attribute of the module (as
long as it's weak referencable) is available as an attribute of the pool
itself:</p>

<example><h>Pool attributes</h>
<prog>
from ll.xist import xsc
from ll.xist.ns import html

pool = xsc.Pool(html)
print(pool.img)
</prog>
</example>

<p>This outputs <lit><![CDATA[<element class ll.xist.ns.html:img at 0x3eed00>]]></lit>.</p>

<p>It's possible to chain pools together. When an attribute isn't found in
the first pool, it will be looked up in a second pool (the so called base
pool):</p>

<example><h>Pool chaining</h>
<prog>
from ll.xist import xsc
from ll.xist.ns import html, svg

hpool = xsc.Pool(html)
spool = xsc.Pool(svg, hpool)
print(spool.img)
</prog>
</example>

<p>Here the <lit>hpool</lit> (containing the <mod>html</mod> namespace)
will be used when the attribute can't be found in <lit>spool</lit>. So this
will again give the output
<lit><![CDATA[<element class ll.xist.ns.html:img at 0x3eed00>]]></lit>.</p>

<p>It's possible to get automatic pool chaining. If a module has an attribute
<lit>__bases__</lit> (which must be a sequence of modules), they will
be wrapped in a pool automatically and used as the base pools for the pool
created for the first module. This makes it possible to <z>overwrite</z> element
classes in existing namespaces. For example to replace the <class>a</class>
class in <mod>ll.xist.ns.html</mod>, put the following into a module
<mod>html2</mod>:</p>

<example><h>Automatic pool chaining (<file>html2.py</file>)</h>
<prog>
from ll.xist.ns import html

__bases__ = [html]

class a(html.a):
	xmlns = html.xmlns

	def convert(self, converter):
		node = html.a(self.content, self.attrs, target="_top")
		return node.convert(converter)
</prog>
</example>

<p>Now you can use the module in a pool:</p>

<example><h>Using a pool chain</h>
<prog>
from ll.xist import xsc
import html2

pool = xsc.Pool(html2)
print(pool.a, pool.b)
</prog>
</example>

<p>This outputs:</p>
<tty><![CDATA[
<element class html2:a at 0x113ec40> <element class ll.xist.ns.html:b at 0x1101fe0>
]]></tty>

<p>Note that such a chained pool can of course be used when parsing &xml;. The
parser will recursively search for the first class that has the appropriate
name when instantiating the tree nodes.</p>

</section>


<section><h>Conversion targets</h>

<p>The <obj>converter</obj> argument passed to the <meth>convert</meth>
method has an attribute <lit>target</lit> which is a module or pool and
specifies the target namespace to which <self/> should be converted.</p>

<p>You can check which conversion is wanted by checking e.g. the
<lit>xmlns</lit> attribute. Once this is determined you can use element classes
from the target to create the required &xml; object tree. This makes it possible
to customize the conversion by passing a chained pool to the
<meth>convert</meth> method that extends an existing namespace.</p>

<p>The following example shows how an element be converted to two
different targets:</p>

<example><h>Using conversion targets</h>
<prog>
from ll.xist import xsc
from ll.xist.ns import html, fo

class bold(xsc.Element):
	def convert(self, converter):
		if converter.target.xmlns == html.xmlns:
			node = converter.target.b(self.content)
		elif converter.target.xmlns == fo.xmlns:
			node = converter.target.inline(self.content, font_weight="bold")
		else:
			raise TypeError("unsupported conversion target {!r}".format(converter.target))
		return node.convert(converter)
</prog>
</example>

<p>The default target for conversion is <mod>ll.xist.ns.html</mod>.
Other targets can be specified via the <obj>target</obj> argument in the
<class>Converter</class> constructor or the <meth>conv</meth> method:</p>

<tty>
<prompt>>>> </prompt><input>from ll.xist.ns import html, fo</input>
<prompt>>>> </prompt><input>import foo</input> # This is the code from above
<prompt>>>> </prompt><input>print(foo.bold("foo").conv().string())</input>
<![CDATA[<b>foo</b>]]>
<prompt>>>> </prompt><input>print(foo.bold("foo").conv(target=html).string())</input>
<![CDATA[<b>foo</b>]]>
<prompt>>>> </prompt><input>print(foo.bold("foo").conv(target=fo).string())</input>
<![CDATA[<inline font-weight="bold">foo</inline>]]>
</tty>
</section>


<section><h>Validation and content models</h>

<p>When generating &html; you might want to make sure that your generated
code doesn't contain any illegal element nesting (i.e. something bad like
<markup>&lt;p&gt;&lt;p&gt;foo&lt;/p&gt;&lt;/p&gt;</markup> in &html;). The module
<mod>ll.xist.ns.html</mod> does this automatically:</p>

<example>
<tty>
<prompt>&gt;&gt;&gt; </prompt><input>from ll.xist.ns import html</input>
<prompt>&gt;&gt;&gt; </prompt><input>node = html.p(html.p(u"foo"))</input>
<prompt>&gt;&gt;&gt; </prompt><input>print(node.string())</input>
/Users/walter/checkouts/LivingLogic.Python.xist/src/ll/xist/sims.py:222: \
WrongElementWarning: element &lt;ll.xist.ns.html.p element object (1 child/no attrs) at 0x270b30&gt; \
may not contain element &lt;ll.xist.ns.html.p element object (1 child/no attrs) at 0x69850&gt;
  warnings.warn(WrongElementWarning(node, child, self.elements))
&lt;p&gt;&lt;p&gt;foo&lt;/p&gt;&lt;/p&gt;
</tty>
</example>

<p>For your own elements you can specify the content model too. This is done
by setting the class attribute <lit>model</lit> inside the element class.
<lit>model</lit> must be an object that provides a <meth>checkvalid</meth>
method. This method will be called during parsing or publishing with the element
as an argument. When invalid content is detected, the Python warning framework
should be used to issue a warning.</p>

<p>The module <mod>ll.xist.sims</mod> contains several classes that
provide simple validation methods:
<pyref module="ll.xist.sims" class="Empty"><class>Empty</class></pyref>
can be used to ensure that the element doesn't have any content (like
<markup>br</markup> and <markup>img</markup> in &html;).
<pyref module="ll.xist.sims" class="Any"><class>Any</class></pyref>
does allow any content.
<pyref module="ll.xist.sims" class="NoElements"><class>NoElements</class></pyref>
will warn about elements from the same namespace (elements from other namespaces
will be OK).
<pyref module="ll.xist.sims" class="NoElementsOrText"><class>NoElementsOrText</class></pyref>
will warn about elements from the same namespace and non-whitespace text content.
<pyref module="ll.xist.sims" class="Elements"><class>Elements</class></pyref>
will only allow the elements specified in the constructor.
<pyref module="ll.xist.sims" class="ElementsOrText"><class>ElementsOrText</class></pyref>
will only allow the elements specified in the constructor and text.</p>

<p>None of these classes will check the number of child elements or their
order.</p>

<p>For more info see the <pyref module="ll.xist.sims"><mod>sims</mod></pyref>
module.</p>
</section>
</spc:wrap>
