Commits

Lynn Rees committed 6804648

- reorg

  • Participants
  • Parent commits 78e623d
  • Branches webstring

Comments (0)

Files changed (57)

+syntax:glob
+*.pyc
+*.egg-info
+*~
+.figleaf
+.coverage
+build/
+dist/
+
 syntax: glob
-
-*.pyc
-*~
-.DS_Store
-*.pyo
+.project
+syntax: glob
+.pydevproject
+webstring is a template engine where Python is the template language.
+
+webstring's CheeseShop page is:
+
+http://cheeseshop.python.org/pypi/webstring/
+
+More information on webstring, including documentation and an introductory tutorial, can be found at:
+
+http://psilib.sourceforge.net/webstring.html
+
+Major changes in 0.5 include:
+
+- templating support for non-XML text formats
+- the ability to use lxml as the XML processing library for XML templates
+- the inclusion of a TurboGears/Buffet compatible template plug-in
+- xinclude support (using lxml as the XML processing library)
+- can apply XSLT stylesheets to any part of an XML template using the transform method (using lxml as the XML processing library)
+- the replication operator (*) now repeats the current state of a template instead of the default state
+- the order in which XML elements are concatenated (+) with other XML elements is now preserved 
+- decorators for WSGI templating middleware
+- cElementTree and lxml-based XML templates are properly pickled
+#!python
+"""Bootstrap setuptools installation
+
+If you want to use setuptools in your package's setup.py, just include this
+file in the same directory with it, and add this to the top of your setup.py::
+
+    from ez_setup import use_setuptools
+    use_setuptools()
+
+If you want to require a specific version of setuptools, set a download
+mirror, or use an alternate download directory, you can do so by supplying
+the appropriate options to ``use_setuptools()``.
+
+This file can also be run as a script to install or upgrade setuptools.
+"""
+import sys
+DEFAULT_VERSION = "0.6c7"
+DEFAULT_URL     = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
+
+md5_data = {
+    'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
+    'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
+    'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
+    'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
+    'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
+    'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
+    'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
+    'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
+    'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
+    'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
+    'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
+    'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
+    'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
+    'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
+    'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
+    'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',
+    'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',
+    'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',
+    'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
+    'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
+    'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
+    'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
+    'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
+    'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
+    'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',
+    'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',
+    'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',
+}
+
+import sys, os
+
+def _validate_md5(egg_name, data):
+    if egg_name in md5_data:
+        from md5 import md5
+        digest = md5(data).hexdigest()
+        if digest != md5_data[egg_name]:
+            print >>sys.stderr, (
+                "md5 validation of %s failed!  (Possible download problem?)"
+                % egg_name
+            )
+            sys.exit(2)
+    return data
+
+
+def use_setuptools(
+    version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
+    download_delay=15
+):
+    """Automatically find/download setuptools and make it available on sys.path
+
+    `version` should be a valid setuptools version number that is available
+    as an egg for download under the `download_base` URL (which should end with
+    a '/').  `to_dir` is the directory where setuptools will be downloaded, if
+    it is not already available.  If `download_delay` is specified, it should
+    be the number of seconds that will be paused before initiating a download,
+    should one be required.  If an older version of setuptools is installed,
+    this routine will print a message to ``sys.stderr`` and raise SystemExit in
+    an attempt to abort the calling script.
+    """
+    try:
+        import setuptools
+        if setuptools.__version__ == '0.0.1':
+            print >>sys.stderr, (
+            "You have an obsolete version of setuptools installed.  Please\n"
+            "remove it from your system entirely before rerunning this script."
+            )
+            sys.exit(2)
+    except ImportError:
+        egg = download_setuptools(version, download_base, to_dir, download_delay)
+        sys.path.insert(0, egg)
+        import setuptools; setuptools.bootstrap_install_from = egg
+
+    import pkg_resources
+    try:
+        pkg_resources.require("setuptools>="+version)
+
+    except pkg_resources.VersionConflict, e:
+        # XXX could we install in a subprocess here?
+        print >>sys.stderr, (
+            "The required version of setuptools (>=%s) is not available, and\n"
+            "can't be installed while this script is running. Please install\n"
+            " a more recent version first.\n\n(Currently using %r)"
+        ) % (version, e.args[0])
+        sys.exit(2)
+
+def download_setuptools(
+    version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
+    delay = 15
+):
+    """Download setuptools from a specified location and return its filename
+
+    `version` should be a valid setuptools version number that is available
+    as an egg for download under the `download_base` URL (which should end
+    with a '/'). `to_dir` is the directory where the egg will be downloaded.
+    `delay` is the number of seconds to pause before an actual download attempt.
+    """
+    import urllib2, shutil
+    egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
+    url = download_base + egg_name
+    saveto = os.path.join(to_dir, egg_name)
+    src = dst = None
+    if not os.path.exists(saveto):  # Avoid repeated downloads
+        try:
+            from distutils import log
+            if delay:
+                log.warn("""
+---------------------------------------------------------------------------
+This script requires setuptools version %s to run (even to display
+help).  I will attempt to download it for you (from
+%s), but
+you may need to enable firewall access for this script first.
+I will start the download in %d seconds.
+
+(Note: if this machine does not have network access, please obtain the file
+
+   %s
+
+and place it in this directory before rerunning this script.)
+---------------------------------------------------------------------------""",
+                    version, download_base, delay, url
+                ); from time import sleep; sleep(delay)
+            log.warn("Downloading %s", url)
+            src = urllib2.urlopen(url)
+            # Read/write all in one block, so we don't create a corrupt file
+            # if the download is interrupted.
+            data = _validate_md5(egg_name, src.read())
+            dst = open(saveto,"wb"); dst.write(data)
+        finally:
+            if src: src.close()
+            if dst: dst.close()
+    return os.path.realpath(saveto)
+
+def main(argv, version=DEFAULT_VERSION):
+    """Install or upgrade setuptools and EasyInstall"""
+
+    try:
+        import setuptools
+    except ImportError:
+        egg = None
+        try:
+            egg = download_setuptools(version, delay=0)
+            sys.path.insert(0,egg)
+            from setuptools.command.easy_install import main
+            return main(list(argv)+[egg])   # we're done here
+        finally:
+            if egg and os.path.exists(egg):
+                os.unlink(egg)
+    else:
+        if setuptools.__version__ == '0.0.1':
+            # tell the user to uninstall obsolete version
+            use_setuptools(version)
+
+    req = "setuptools>="+version
+    import pkg_resources
+    try:
+        pkg_resources.require(req)
+    except pkg_resources.VersionConflict:
+        try:
+            from setuptools.command.easy_install import main
+        except ImportError:
+            from easy_install import main
+        main(list(argv)+[download_setuptools(delay=0)])
+        sys.exit(0) # try to force an exit
+    else:
+        if argv:
+            from setuptools.command.easy_install import main
+            main(argv)
+        else:
+            print "Setuptools version",version,"or greater has been installed."
+            print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
+
+
+
+def update_md5(filenames):
+    """Update our built-in md5 registry"""
+
+    import re
+    from md5 import md5
+
+    for name in filenames:
+        base = os.path.basename(name)
+        f = open(name,'rb')
+        md5_data[base] = md5(f.read()).hexdigest()
+        f.close()
+
+    data = ["    %r: %r,\n" % it for it in md5_data.items()]
+    data.sort()
+    repl = "".join(data)
+
+    import inspect
+    srcfile = inspect.getsourcefile(sys.modules[__name__])
+    f = open(srcfile, 'rb'); src = f.read(); f.close()
+
+    match = re.search("\nmd5_data = {\n([^}]+)}", src)
+    if not match:
+        print >>sys.stderr, "Internal error!"
+        sys.exit(2)
+
+    src = src[:match.start(1)] + repl + src[match.end(1):]
+    f = open(srcfile,'w')
+    f.write(src)
+    f.close()
+
+
+if __name__=='__main__':
+    if len(sys.argv)>2 and sys.argv[1]=='--md5update':
+        update_md5(sys.argv[2:])
+    else:
+        main(sys.argv[1:])
+
+
+
+
+
+# Copyright (c) 2006 L. C. Rees.  All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1.  Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# 2.  Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3.  Neither the name of the Portable Site Information Project nor the names
+# of its contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+'''setup - setuptools based setup for webstring'''
+
+import ez_setup
+ez_setup.use_setuptools()
+
+try:
+    from setuptools import setup
+except:
+    from distutils.core import setup
+
+setup(name='webstring',
+      version='0.5',
+      description='''Template engine that uses Python as the template language''',
+      long_description='''A template engine that uses Python as the template language.''',
+      author='L. C. Rees',
+      author_email='lcrees@gmail.com',
+      url='http://psilib.sourceforge.net/webstring.html',
+      license='BSD',
+      packages = ['webstring', 'webstring.ext', 'webstring.tests'],
+      zip_safe = True,
+      keywords='template text XML HTML XHTML meld TurboGears WSGI',
+      classifiers=['Development Status :: 4 - Beta',
+                    'Environment :: Web Environment',
+                    'Intended Audience :: Developers', 
+                    'Framework :: TurboGears',
+                    'License :: OSI Approved :: BSD License',
+                    'Natural Language :: English',
+                    'Operating System :: OS Independent',
+                    'Programming Language :: Python',
+                    'Topic :: Internet :: WWW/HTTP',
+                    'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
+                    'Topic :: Text Processing',
+                    'Topic :: Text Processing :: Markup :: HTML',
+                    'Topic :: Text Processing :: Markup :: XML'],
+      entry_points='''
+      [python.templating.engines]
+      webstring = webstring.ext.turbogears:TurboWebstring
+      lwebstring = webstring.ext.turbogears:TurboWebstring
+      ''',
+      install_requires = ['lxml==1.1.1'])

File webstring/README

-webstring is a template engine where Python is the template language.
-
-webstring's CheeseShop page is:
-
-http://cheeseshop.python.org/pypi/webstring/
-
-More information on webstring, including documentation and an introductory tutorial, can be found at:
-
-http://psilib.sourceforge.net/webstring.html
-
-Major changes in 0.5 include:
-
-- templating support for non-XML text formats
-- the ability to use lxml as the XML processing library for XML templates
-- the inclusion of a TurboGears/Buffet compatible template plug-in
-- xinclude support (using lxml as the XML processing library)
-- can apply XSLT stylesheets to any part of an XML template using the transform method (using lxml as the XML processing library)
-- the replication operator (*) now repeats the current state of a template instead of the default state
-- the order in which XML elements are concatenated (+) with other XML elements is now preserved 
-- decorators for WSGI templating middleware
-- cElementTree and lxml-based XML templates are properly pickled

File webstring/__init__.py

+# Copyright (c) 2006 L. C. Rees.  All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1.  Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# 2.  Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3.  Neither the name of the Portable Site Information Project nor the names
+# of its contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+'''Template engine where Python is the template language.''' 
+
+__author__ = 'L.C. Rees (lcrees-at-gmail.com)'
+__revision__ = '0.5'
+
+from webstring.xmlt import *
+from webstring.html import *
+from webstring.text import *
+
+
+class Template(object):
+
+    '''Template dispatcher class.'''
+    
+    def __new__(cls, *args, **kw):
+        '''Returns a template class.'''
+        format = kw.get('format', 'xml')
+        if format == 'xml':
+            return XMLTemplate(*args, **kw)
+        elif format == 'html':
+            return HTMLTemplate(*args, **kw)
+        elif format == 'text':
+            return TextTemplate(*args, **kw)

File webstring/base.py

+# Copyright (c) 2006 L. C. Rees.  All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1.  Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# 2.  Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3.  Neither the name of the Portable Site Information Project nor the names
+# of its contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+'''Base webstring Template classes.'''
+
+import string
+from keyword import kwlist
+
+__all__ = ['_Template', '_Group', '_Field', '_checkname']
+
+# Exceptions
+_exceptions = ['maximum allowed repetitions exceeded',
+    'invalid Template source',
+    'invalid type for formatting',
+    'not all arguments converted during formatting',
+    'not enough arguments for format', '', '',
+    'invalid inline template source',
+    'delimiter "$" or "%" not found',
+    'invalid Template filter type']
+_Stemplate = string.Template
+# Illegal characters for Python names
+_ichar = '()[]{}@,:.`=;+-*/%&|^><\'"#\\$?!~'
+# Reserve webstring specific words
+kwlist.extend(['append', 'atemplates', 'current', 'default', 'exclude',
+    'fromfile', 'fromstring', 'groupmark', 'include', 'mark', 'max', 'pipe',
+    'purge', 'render', 'repeat', 'reset', 'template', 'templates', 'text',
+    'update', 'write'])
+_reserve, _keywords = string.maketrans('', ''), frozenset(kwlist)
+
+def _checkname(name):
+    '''Ensures a string is a legal Python name.'''
+    # Remove characters that are illegal in a Python name
+    if '}' not in name:
+        name = name.replace('.', '_').translate(_reserve, _ichar)
+    # Handle XML namespaced names
+    else:
+        name = name.split('}')[1].replace('.', '_').translate(_reserve, _ichar)
+    # Add _ if value is a Python keyword
+    if name in _keywords: return ''.join([name, '_'])
+    return name
+    
+
+class _Base(object):
+
+    '''Template base class.'''
+
+    def __init__(self, auto, **kw):
+        # Controls if templates become object attrs of a root/group Template
+        self._auto = auto
+
+    def __repr__(self):
+        '''String representation of a Template.'''
+        return '<Template "%s" at %x>' % (self.__name__, id(self))
+
+    def __str__(self):
+        '''String output of a Template.'''
+        return self.render()
+
+    def __add__(self, data):
+        '''Inserts data or another Template's fields after the internal
+        template and returns a modified copy of the Template.
+        '''
+        self.__iadd__(data)
+        newself = self.current
+        self.reset()
+        return newself
+
+    def __radd__(self, data):
+        '''__add__ from the right.'''
+        return self.__add__(data)
+   
+    def __mul__(self, num):
+        '''Inserts a copy of the internal field after the internal field 
+        "num" number of times and returns a modified copy of the Template.
+        '''
+        self.__imul__(num)
+        newself = self.current
+        self.reset()
+        return newself
+
+    def __rmul__(self, num):
+        '''__mul__ from the right.'''
+        return self.__mul__(num)
+        
+    def __imul__(self, num):
+        '''Inserts a copy of the internal field after the internal field 
+        "num" number of times and the Template (self) is returned modified.
+        '''
+        # Ensure "num" is not greater than maximum allowed repetitions
+        if num <= self.max:            
+            tmp = self.current
+            # Concatenate "number" number of copies of self to self
+            for number in xrange(num-1): self.__iadd__(tmp.current)
+            return self
+        raise TypeError(_exceptions[0])
+
+    def __mod__(self, data):
+        '''Substitutes text data into the internal template and returns a
+        modified copy of the Template.
+        '''
+        self.__imod__(data)
+        newself = self.current
+        self.reset()
+        return newself
+               
+    def __pow__(self, data):
+        '''For each item in a tuple, the internal template is copied, the
+        item is substituted into the copy's template, and the copy is inserted
+        after the internal template. Finally, a modified copy of the Template
+        is returned.
+        '''
+        self.__ipow__(data)
+        newself = self.current
+        self.reset()
+        return newself
+
+    def __ipow__(self, data):
+        '''For each item in a tuple, the internal template is copied, the 
+        content of the item is substituted into the copy's template, and
+        the copy is inserted after the internal template. Finally, the modified
+        Template (self) is returned.
+        '''
+        if len(data) <= self.max:
+            if isinstance(data, tuple):
+                # Put data in correct order
+                data = list(reversed(data))
+            else:
+                raise TypeError('invalid type for formatting')
+            # Substitute content into existing field
+            self.__imod__(data.pop())
+            # Concatenate a new field with self for each item
+            while data: self.repeat(data.pop())
+            return self                
+        # Raise exception if data length > maximum allowed repetitions
+        raise TypeError(_exceptions[0])
+
+    def _setmark(self, mark):
+        '''Sets template variable delimiter.'''
+        self._mark = mark
+
+    def pipe(self, info=None, format='xml', encoding='utf-8'):
+        '''Returns the string output of the internal template and
+        resets the Template.
+
+        @param info Data to substitute into a template (default: None)
+        @param format Document format (default:'xml')
+        @param encoding Encoding of return string (default: 'utf-8')
+        '''
+        output = self.render(info, format, encoding)
+        self.reset()
+        return output
+
+    def repeat(self, data=None):
+        '''Copies the original state of the internal template, inserts it after
+        the interal template, and, optionally, substitutes data into it.
+
+        @data data Data to substitute into a template (default: None)
+        '''
+        if data is not None:
+            self.__iadd__(self.default.__imod__(data))
+        else:
+            self.__iadd__(self.default)
+            
+    def write(self, path, info=None, format='xml', encoding='utf-8'):
+        '''Writes a Template's string output to a file.
+
+        @param path Output file path
+        @param info Data to substitute into a template (default: None)
+        @param format Document format (default:'xml')
+        @param encoding Encoding of output string (default: 'utf-8')
+        '''
+        open(path, 'wb').write(self.render(info, format, encoding))
+
+
+class _Many(_Base):
+
+    '''Base class for Templates with subtemplates (groups or fields).'''
+
+    def __init__(self, auto, omax, **kw):
+        super(_Many, self).__init__(auto, **kw)
+        # Sets maximum allowed repetitions of a Template
+        self._max = omax
+        # Internal tracking structures
+        self._fielddict, self._fields, self._filter = dict(), list(), set()
+
+    def __imod__(self, data):
+        '''Substitutes text data into each field's template and the
+        modified Template (self) is returned.
+        '''
+        # Get any templates
+        try:
+            self.templates(data.pop('templates'))
+        except (AttributeError, KeyError): pass
+        # Get any substitutions
+        try:
+            self.__ipow__(data.pop('subs'))
+        except (AttributeError, KeyError): pass
+        # Cache field and data length
+        lself, length = len(self._fields), len(data)
+        # If number of fields == number of items in data...
+        if length == lself:
+            if isinstance(data, dict):                
+                for key, value in data.iteritems():
+                    # If tuple, expand it
+                    try:
+                        self._fielddict[key].__ipow__(value)
+                    # If dictionary, substitute it
+                    except TypeError:
+                        self._fielddict[key].__imod__(value) 
+            elif isinstance(data, tuple):
+                # Iterate with index and item through data
+                for key, item in enumerate(data):
+                    # If item is a tuple, expand it
+                    try:
+                        self._fields[key].__ipow__(item)
+                    # If dictionary, substitute it
+                    except TypeError:
+                        self._fields[key].__imod__(item)
+            else:
+                raise TypeError(_exceptions[2])
+        # Return self if no more items in data
+        elif length == 0:
+            return self
+        # Raise exception if too many items to match all fields
+        elif length > lself:
+            raise TypeError(_exceptions[3])
+        # Raise exception if too few items to match all fields
+        elif length < lself:
+            raise TypeError(_exceptions[4])        
+        return self 
+
+    def __getitem__(self, key):
+        '''Gets a field by position or keyword.'''
+        # Try getting field by position from list
+        try:
+            return self._fields[key]
+        # Try getting field by keyword from dictionary
+        except TypeError:
+            return self._fielddict[key]
+    
+    def __setitem__(self, key, value):
+        '''Stub'''
+        
+    def __delitem__(self, key):
+        '''Deletes a field.'''
+        # Handle positional indexes
+        try:
+            # Get field
+            obj = self._fields[key] 
+            # Get field name
+            for name, element in self._fielddict.iteritems():
+                if element == obj: break
+        # Handle keys
+        except TypeError:
+            name = key
+        # Delete object attribute
+        self.__delattr__(name)
+
+    def __contains__(self, key):
+        '''Tells if a field of a given name is in a Template.'''
+        return key in self._fielddict        
+
+    def __len__(self):
+        '''Gets the number of fields in a Template.'''
+        return len(self._fields)    
+
+    def __iter__(self):
+        '''Iterator for the internal field list.'''
+        return iter(self._fields)
+
+    def _setfield(self, key, node):
+        '''Sets a new field.'''
+        self._fields.append(node)        
+        self._fielddict[key] = node
+        # Make field attribute of self if automagic on
+        if self._auto: setattr(self, key, node)
+
+    def _setmark(self, mark):
+        '''Sets the variable delimiter for all subtemplates in a Template.'''
+        super(_Many, self)._setmark(mark)
+        # Set variable delimiter on all children
+        for field in self._fields: field.mark = mark          
+
+    def _setgmark(self, mark):
+        '''Sets group delimiter.'''
+        self._groupmark = mark
+
+    def _setmax(self, omax):
+        '''Sets the maximum repetition value for all Templates.'''
+        # Set group or root to max
+        self._max = omax
+        # Set max on all children
+        for field in self._fields: field.max = omax            
+    
+    # Property for setting a maximum repetition value    
+    max = property(lambda self: self._max, _setmax)    
+    
+
+class _Field(_Base):
+
+    '''Field base class.'''
+    
+    def __init__(self, auto, omax, **kw):
+        super(_Field, self).__init__(auto, **kw)
+        # Maximum repetition value and internal trackers
+        self.max, self._siblings = omax, kw.get('siblings', list())
+        self._tempfields = kw.get('tempfields', list())
+
+    def __imod__(self, data):
+        '''Substitutes text data into the internal element's text and
+        attributes and returns this field (self) modified.
+        '''
+        if isinstance(data, basestring):
+            self.text = data
+        elif isinstance(data, dict):            
+            # Try popping inline text content
+            try:
+                self.text = data.pop('text')
+            except KeyError: pass
+            # Try popping substitutions
+            try:
+                self.__ipow__(data.pop('sub'))                
+            except KeyError: pass
+        else:
+            raise TypeError(_exceptions[2])
+        return self
+        
+
+class _Group(_Many):
+
+    '''Group base class.'''    
+
+    def __init__(self, auto, omax, **kw):
+        super(_Group, self).__init__(auto, omax, **kw)
+        # Internal trackers
+        self._siblings = kw.get('siblings', list())
+        self._tempfields = kw.get('tempfields', list())
+
+
+class _Template(_Many):
+
+    '''Base class for root Templates.'''    
+
+    def __init__(self, auto, omax, **kw):
+        super(_Template, self).__init__(auto, omax, **kw)      
+
+    def append(self, data):        
+        '''Makes a string or another Template's internal template part of
+        the Template's internal template.
+
+        @param data Template or element
+        '''
+        self.__iadd__(data)   
+
+    def exclude(self, *args):
+        '''Excludes fields or groups from a Template.
+
+        @param args Names of a field or group
+        '''
+        # Remove fields from root
+        for arg in args:
+            name = _checkname(arg)
+            # Add to internal filter list
+            self._filter.add(name)
+            # Remove field if present
+            self.__delitem__(name)
+        # Remove fields from children
+        for index, field in enumerate(self._fields):
+            # Run only on groups
+            if hasattr(field, 'groupmark'):
+                for arg in args:                    
+                    name = _checkname(arg)
+                    # Remove subfield if present
+                    field.__delitem__(name)                    
+                # Remove empty groups
+                if len(field) == 0: self.__delitem__(index)    
+
+    def include(self, *args):
+        '''Includes a field or group in a Template.
+
+        @param args Names of fields or groups
+        '''
+        # Remove from internal tracker
+        self._filter -= set(args)
+        self.reset()

File webstring/docs/CHANGELOG-0.5

+Changes in 0.5 include:
+
+- templating support for non-XML text formats
+- the ability to use lxml as the XML processing library for XML templates
+- the inclusion of a TurboGears/Buffet compatible template plug-in
+- xinclude support (using lxml as the XML processing library)
+- can apply XSLT stylesheets to any part of an XML template using the transform method (using lxml as the XML processing library)
+- the replication operator (*) now repeats the current state of a template instead of the default state
+- the order in which XML elements are concatenated (+) with other XML elements is now preserved 
+- decorators for WSGI templating middleware
+- cElementTree and lxml-based XML templates are properly pickled

File webstring/docs/seceaddr.gif

Added
New image

File webstring/docs/text.html

+<?xml version="1.0" encoding="utf-8"?>
+<?xml-stylesheet href="webstring.css" type="text/css" media="screen" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>webstring: Introduction to TextTemplate</title>
+<link href="webstring.css" rel="stylesheet" type="text/css" media="screen" />
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+</head>
+<body>
+<div class="toc">
+<div class="entry"><a href="#classes">Class</a></div>
+<div class="entry"><a href="#initialization">Initialization</a></div>
+<div class="entry"><a href="#objects">Objects</a></div>
+<div class="entry"><a href="#dataaccess">Access</a></div>  <div class="entry"><a href="#sub">Substitution</a></div>
+<div class="entry"><a href="#batch">Batch Substitution</a></div>
+<div class="entry"><a href="#state">State</a></div>
+<div class="entry"><a href="#add">Concatenation </a></div>  <div class="entry"><a href="#mul">Repetition</a></div>
+<div class="entry"><a href="#iter">Iteration</a></div>
+<div class="entry"><a href="#out">Output</a></div>
+</div>
+<div class="header"><img class="headerimg" src="webstring.gif" width="400" height="201" alt="webstring" />
+  <div class="headertext">Introduction to TextTemplate</div></div>
+<div class="textheader"><a id="classes">CLASS</a></div>
+<div class="textblock">While<em> webstring's </em>other specialized classes  
+  only handle XML and HTML templating, TextTemplate can handle templating for 
+  any text format, including XML and HTML.<br />
+  <br />
+  TextTemplate can be used as a standalone import: </div>
+  <div class="codeblock"><pre>&gt;&gt;&gt; <span class="keyword">from</span> webstring <span class="keyword">import</span> TextTemplate</pre></div>  
+<div class="textblock">It can also be used through <em>webstring's </em>Template 
+  class,  a  general frontend to all of <em>webstring's</em> specialized 
+  classes.</div>
+<div class="textheader"><a id="initialization">INITIALIZATION</a></div>
+<div class="textblock">A TextTemplate object can be initialized empty:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; exampleA = TextTemplate()</pre></div>
+<div class="textblock">From a file with the <em>fromfile</em> method:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; exampleB.fromfile(<span class="string">'example.rss'</span>)</pre></div>
+<div class="textblock">By passing the path to the file as the first argument to the class constructor:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; exampleC = TextTemplate(<span class="string">'example.rss'</span>)</pre></div>
+<div class="textblock">From a string with the <em>fromstring</em> method:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; exampleD = TextTemplate.fromstring(<span class="string">&quot;&quot;&quot;&lt;rss version=&quot;2.0&quot;&gt;</span><br />...  <span class="string">&lt;channel&gt;</span><br />...   <span class="string">&lt;title&gt;Example&lt;/title&gt;</span><br />...   <span class="string">&lt;link&gt;http://www.example.org/&lt;/link&gt;</span><br />...   <span class="string">&lt;description&gt;RSS Example&lt;/description&gt;</span><br />...   <span class="string">&lt;language&gt;en-us&lt;/language&gt;</span><br />...   <span class="string">$$cpubdate&lt;pubDate&gt;$month$ $day$, $year$&lt;/pubDate&gt;$$</span><br />...   <span class="string">$$lastbuilddate&lt;lastBuildDate&gt;$month$ $day$, $year$&lt;/lastBuildDate&gt;$$</span>
+...   <span class="string">$$item&lt;item&gt;</span><br />...    <span class="string">&lt;title&gt;$title$&lt;/title&gt;</span><br />...    <span class="string">&lt;link&gt;$link$&lt;/link&gt;</span><br />...    <span class="string">&lt;guid isPermaLink=&quot;true&quot;&gt;$guid$&lt;/guid&gt;</span><br />...    <span class="string">&lt;description&gt;$description$&lt;/description&gt;</span><br />...    <span class="string">&lt;pubDate&gt;$ipubdate$&lt;/pubDate&gt;</span><br />...   <span class="string">&lt;/item&gt;</span><br />...  <span class="string">$$&lt;/channel&gt;</span><br />...  <span class="string">&lt;/rss&gt;&quot;&quot;&quot;</span>)</pre></div>
+<div class="textblock">By passing a string as  the first argument  to the class constructor:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example = TextTemplate(<span class="string">&quot;&quot;&quot;&lt;rss version=&quot;2.0&quot;&gt;</span><br />...  <span class="string">&lt;channel&gt;</span><br />...   <span class="string">&lt;title&gt;Example&lt;/title&gt;</span><br />...   <span class="string">&lt;link&gt;http://www.example.org/&lt;/link&gt;</span><br />...   <span class="string">&lt;description&gt;RSS Example&lt;/description&gt;</span><br />...   <span class="string">&lt;language&gt;en-us&lt;/language&gt;</span><br />...   <span class="string">$$cpubdate&lt;pubDate&gt;$month$ $day$, $year$&lt;/pubDate&gt;$$</span><br />...   <span class="string">$$lastbuilddate&lt;lastBuildDate&gt;$month$ $day$, $year$&lt;/lastBuildDate&gt;$$</span>
+...   <span class="string">$$item&lt;item&gt;</span><br />...    <span class="string">&lt;title&gt;$title$&lt;/title&gt;</span><br />...    <span class="string">&lt;link&gt;$link$&lt;/link&gt;</span><br />...    <span class="string">&lt;guid isPermaLink=&quot;true&quot;&gt;$guid$&lt;/guid&gt;</span><br />...    <span class="string">&lt;description&gt;$description$&lt;/description&gt;</span><br />...    <span class="string">&lt;pubDate&gt;$ipubdate$&lt;/pubDate&gt;</span><br />...   <span class="string">&lt;/item&gt;</span><br />...  <span class="string">$$&lt;/channel&gt;</span><br />...  <span class="string">&lt;/rss&gt;&quot;&quot;&quot;</span>)</pre></div>
+<div class="textblock">To use TextTemplate through  the  Template class, you 
+  pass the value <em>text </em> with the <em>format</em> keyword to the Template class's constructor:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example = Template(format="text")</pre></div>	    
+<div class="textheader"><a id="objects">OBJECTS</a></div>
+<div class="textblock"><em>webstring</em> automatically maps a template to a root 
+  object. Field placeholders within the template are an alphanumeric value that 
+  uniquely identifies the field placeholder within the template preceded and terminated 
+  by a placeholder marker (by default, <strong>$</strong>). Field placeholders 
+  are automatically mapped to field objects with the same name as the field placeholder 
+  and attached to the parent template's root object.</div>
+<div class="codeblock"><pre class="stdout">$$cpubdate&lt;pubDate&gt;<span class="highlight">$month$</span> $day$, $year$&lt;/pubDate&gt;$$</pre></div>
+<div class="textblock">Group placeholders within the template are blocks of text 
+  containing field placeholders preceded and terminated by a group placeholder 
+  marker (by default, <strong>$$</strong>). The alphanumeric value immediately 
+  following the opening group placeholder marker uniquely identifies the group 
+  within the template. <em>webstring</em> automatically maps the group placeholder 
+  to a group object with the same name as the group placeholder and attaches it 
+  to the parent template's root object. Field placeholders within group are mapped 
+  to field objects and attached to the group object.</div>
+<div class="codeblock"><pre class="stdout"><span class="highlight">$$cpubdate</span>&lt;pubDate&gt;$month$ $day$, $year$&lt;/pubDate&gt;<span class="highlight">$$</span></pre></div>
+<div class="textblock">Group objects cannot contain other group objects. At maximum, a root's object hierarchy will never be more than three levels deep.<br />
+  <br />Root level:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example<br /><span class="stdout">&lt;Template &quot;root&quot; at db7dd0&gt;</span></pre></div>
+<div class="textblock">Group level:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.item<br /><span class="stdout">&lt;Template &quot;item&quot; at f5d870&gt;</span></pre></div>
+<div class="textblock">Field level:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.item.guid<br /><span class="stdout">&lt;Template &quot;guid&quot; at f5da70&gt;</span></pre></div>
+<div class="textblock">At minimum, a root object's depth will only be two levels deep.<br /><br />Root level:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example<br /><span class="stdout">&lt;Template &quot;root&quot; at db7dd0&gt;</span></pre></div>
+<div class="textblock">Field level:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.cpubdate<br /><span class="stdout">&lt;Template &quot;cpubdate&quot; at e7a350&gt;</span></pre></div>
+<div class="textblock">By default, all field or group placeholders become part 
+  of a root's object hierarchy except for groups that have no field placeholders 
+  within them. However, existing fields or groups within an template can be excluded 
+  or included before or after a root object is initialized by using its <em>exclude</em> 
+  or <em>include</em> methods.<br />
+  <br />
+  Exclusion with the <em>exclude</em> method:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.exclude(<span class="string">'cpubdate'</span>) <br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;lastBuildDate&gt; , &lt;/lastBuildDate&gt;<br />  &lt;item&gt;<br />   &lt;title&gt;&lt;/title&gt;<br />   &lt;link&gt;&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;&lt;/guid&gt;<br />   &lt;description&gt;&lt;/description&gt;<br />   &lt;pubDate&gt;&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">Inclusion with the <em>include</em> method:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.include(<span class="string">'cpubdate'</span>)<br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  </span><span class="highlight">&lt;pubDate&gt; , &lt;/pubDate&gt;</span><span class="stdout"><br />  &lt;lastBuildDate&gt; , &lt;/lastBuildDate&gt;
+  &lt;item&gt;<br />   &lt;title&gt;&lt;/title&gt;<br />   &lt;link&gt;&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;&lt;/guid&gt;<br />   &lt;description&gt;&lt;/description&gt;<br />   &lt;pubDate&gt;&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">Fields and groups can  be removed by deleting
+  their object attribute:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; <span class="keyword">del</span> example.cpubdate<br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;lastBuildDate&gt; , &lt;/lastBuildDate&gt;<br />  &lt;item&gt;<br />   &lt;title&gt;&lt;/title&gt;<br />   &lt;link&gt;&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;&lt;/guid&gt;<br />   &lt;description&gt;&lt;/description&gt;<br />   &lt;pubDate&gt;&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">A root, field, or group can be set back to its default state by calling
+  its <em>reset</em> method:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.reset()<br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate&gt; , &lt;/pubDate&gt;<br />  &lt;lastBuildDate&gt; , &lt;/lastBuildDate&gt;
+  &lt;item&gt;<br />   &lt;title&gt;&lt;/title&gt;<br />   &lt;link&gt;&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;&lt;/guid&gt;<br />   &lt;description&gt;&lt;/description&gt;<br />   &lt;pubDate&gt;&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textheader"><a id="dataaccess">ACCESS</a></div>
+<div class="textblock">Fields can be accessed by object attribute:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.cpubdate<br /><span class="stdout">&lt;Template &quot;cpubdate&quot; at e7a350&gt;</span></pre></div>
+<div class="textblock">By keyword:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example[<span class="string">'cpubdate'</span>]<br /><span class="stdout">&lt;Template &quot;cpubdate&quot; at e7a350&gt;</span></pre></div>
+<div class="textblock">By position:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example[<span class="int">0</span>]<br /><span class="stdout">&lt;Template &quot;cpubdate&quot; at e7a350&gt;</span></pre></div>
+<div class="textblock">Groups are accessed the same way:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.item <br /><span class="stdout">&lt;Template &quot;item&quot; at f5d870&gt;</span><br />&gt;&gt;&gt; example[<span class="string">'item'</span>]<br /><span class="stdout">&lt;Template &quot;item&quot; at f5d870&gt;</span><br />&gt;&gt;&gt; example[<span class="int">2</span>]<br /><span class="stdout">&lt;Template &quot;item&quot; at f5d870&gt;</span></pre></div>
+<div class="textblock">Fields within a group are accessed by combining its identifier and  its group identifier:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.item.title <br /><span class="stdout">&lt;Template &quot;title&quot; at f5d9b0&gt;</span><br />&gt;&gt;&gt; example[<span class="string">'item'</span>][<span class="string">'title'</span>]<br /><span class="stdout">&lt;Template &quot;title&quot; at f5d9b0&gt;</span><br />&gt;&gt;&gt; example[<span class="int">2</span>][<span class="int">0</span>]<br /><span class="stdout">&lt;Template &quot;title&quot; at f5d9b0&gt;</span></pre></div>
+<div class="textblock">By default, <em>webstring</em> automatically maps fields, 
+  groups, and attributes to object attributes with the same name as the field 
+  or group placeholder's identifier. This &quot;auto-magical&quot; behavior can 
+  be disabled by passing a boolean value of <span class="keyword">False</span> 
+  to the class constructor as the second argument when a TextTemplate object is 
+  initialized:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; exampleZ = TextTemplate(<span class="string">'example.rss', </span><span class="keyword">False</span>)</pre></div>
+<div class="textblock">Fields and groups can then be accessed by keyword or position 
+  but not by named object attribute.</div>
+<div class="textheader"><a id="sub">SUBSTITUTION</a></div>
+<div class="textblock">Text can be substituted into a field by assigning a string to a field's text property:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.item.description.text = <span class="string">'Assigning text to a field.'</span>
+&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate&gt; , &lt;/pubDate&gt;<br />  &lt;lastBuildDate&gt; , &lt;/lastBuildDate&gt;
+  &lt;item&gt;<br />   &lt;title&gt;&lt;/title&gt;<br />   &lt;link&gt;&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;&lt;/guid&gt;<br />   &lt;description&gt;</span><span class="highlight">Assigning text to a field.</span><span class="stdout">&lt;/description&gt;<br />   &lt;pubDate&gt;&lt;/pubDate&gt;<br />  &lt;/item&gt;<br />  &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">Alternatively, text can be substituted into a field using 
+  the modulo assignment operator (<strong>%=</strong>). Using the modulo operator without the assignment operator 
+    (<strong>%</strong>) creates a new object. Using the modulo operator with 
+    the assignment operator (<strong>%=</strong>) modifies the left-hand object.</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.item.description %= <span class="string">'Example of assigning text to a field.'</span>
+&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate&gt; , &lt;/pubDate&gt;<br />  &lt;lastBuildDate&gt; , &lt;/lastBuildDate&gt;
+  &lt;item&gt;<br />   &lt;title&gt;&lt;/title&gt;<br />   &lt;link&gt;&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;&lt;/guid&gt;<br />   &lt;description&gt;</span><span class="highlight">Example of assigning text to a field.</span><span class="stdout">&lt;/description&gt;<br />   &lt;pubDate&gt;&lt;/pubDate&gt;<br />  &lt;/item&gt;<br />  &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">The <strong>%= </strong>operator can also be used to substitute 
+  text into a group using a dictionary containing key/value pairs where the key is the name of the field 
+  inside the group and the value is the text that will be assigned to the field:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.cpubdate %= {<span class="string">'month'</span>:<span class="string">'June'</span>, <span class="string">'day'</span>:<span class="string">'06'</span>, <span class="string">'year'</span>:<span class="string">'2006'</span>}
+&gt;&gt;&gt; example.lastbuilddate %= {<span class="string">'month'</span>:<span class="string">'June'</span>, <span class="string">'day'</span>:<span class="string">'06'</span>, <span class="string">'year'</span>:<span class="string">'2006'</span>}<br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate&gt;</span><span class="highlight">June 06, 2006</span><span class="stdout">&lt;/pubDate&gt;<br />  &lt;lastBuildDate&gt;</span><span class="highlight">June 06, 2006</span><span class="stdout">&lt;/lastBuildDate&gt;
+  &lt;item&gt;<br />   &lt;title&gt;&lt;/title&gt;<br />   &lt;link&gt;&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;&lt;/guid&gt;<br />   &lt;description&gt;Example of assigning text to a field.&lt;/description&gt;<br />   &lt;pubDate&gt;&lt;/pubDate&gt;</span><span class="stdout"><br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textheader"><a id="batch">BATCH SUBSTITUTION</a></div>
+<div class="textblock">The modulo operator can also be used to substitute text into a template in 
+    one batch substitution. 
+    Text values for fields and groups within a template are passed in a dictionary 
+    containing key/value pairs where the key is the field or group identifier 
+    and the value is the text to be substituted. Fields within a group are passed 
+    in a dictionary that is stored under the keyword identifying the group:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example %= {<br />... <span class="string">'cpubdate'</span>:{<span class="string">'month'</span>:<span class="string">'June'</span>, <span class="string">'day'</span>:<span class="string">'06'</span>, <span class="string">'year'</span>:<span class="string">'2006'</span>}, <br />... <span class="string">'lastbuilddate'</span>:{<span class="string">'month'</span>:<span class="string">'June'</span>, <span class="string">'day'</span>:<span class="string">'06'</span>, <span class="string">'year'</span>:<span class="string">'2006'</span>},<br />... <span class="string">'item'</span>:{<span class="string">'title'</span>:<span class="string">Example Title: First Example'</span>,<br />... 	<span class="string">'link'</span>:'<span class="string">http://www.example.org/rss/5423093'</span>,<br />... 	<span class="string">'guid'</span>:'<span class="string">http://www.example.org/rss/5423093'</span>,<br />... 	<span class="string">'description'</span>:<span class="string">'Example of assigning text to a field.'</span>,<br />... 	<span class="string">'ipubdate'</span>:<span class="string">'June </span><span class="string">6, </span><span class="string">2006'</span>}}<br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate&gt;</span><span class="highlight">June 06, 2006</span><span class="stdout">&lt;/pubDate&gt;<br />  &lt;lastBuildDate&gt;</span><span class="highlight">June 06, 2006</span><span class="stdout">&lt;/lastBuildDate&gt;<br />  &lt;item&gt;<br />   &lt;title&gt;</span><span class="highlight">Example Title: First Example</span><span class="stdout">&lt;/title&gt;<br />   &lt;link&gt;</span><span class="highlight">http://www.example.org/rss/5423093</span><span class="stdout">&lt;/link&gt;<br />   &lt;guid </span><span class="stdout">isPermaLink=&quot;true&quot;&gt;</span><span class="highlight">http://www.example.org/rss/5423093</span><span class="stdout">&lt;/guid&gt;<br />   &lt;description&gt;</span><span class="highlight">Example of assigning text to a field.</span><span class="stdout">&lt;/description&gt;<br />   &lt;pubDate&gt;</span><span class="highlight">June 06, 2006</span><span class="stdout">&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textheader"><a id="state">STATE</a></div>
+<div class="textblock">Each root, field, or group has a <em>current</em> and a <em>default</em> property. The <em>current</em> property returns the object's current state:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.current<br /><span class="stdout">&lt;Template &quot;root&quot; at dcd290&gt;</span><br />&gt;&gt;&gt; <span class="keyword">print</span> example.current<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate&gt;June 06, 2006&lt;/pubDate&gt;<br />  &lt;lastBuildDate&gt;June 06, 2006&lt;/lastBuildDate&gt;<br />  &lt;item&gt;<br />   &lt;title&gt;Example Title: First Example&lt;/title&gt;<br />   &lt;link&gt;http://www.example.org/rss/5423093&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;http://www.example.org/rss/5423093&lt;/guid&gt;<br />   &lt;description&gt;Example of assigning text to a field.&lt;/description&gt;<br />   &lt;pubDate&gt;June 06, 2006&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">The <em>default</em> property returns the object's
+  default state:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.default<br /><span class="stdout">&lt;Template &quot;root&quot; at f62d10&gt;</span><br />&gt;&gt;&gt; <span class="keyword">print</span> example.default<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate&gt; , &lt;/pubDate&gt;<br />  &lt;lastBuildDate&gt; , &lt;/lastBuildDate&gt;
+  &lt;item&gt;<br />   &lt;title&gt;&lt;/title&gt;<br />   &lt;link&gt;&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;&lt;/guid&gt;<br />   &lt;description&gt;&lt;/description&gt;<br />   &lt;pubDate&gt;&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textheader"><a id="add">CONCATENATION</a></div>
+<div class="textblock">Roots, fields, and groups can be concatenated together using the addition operator.<br /><br />Roots:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.reset()<br />&gt;&gt;&gt; <span class="keyword">print</span> example + example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate&gt; , &lt;/pubDate&gt;<br />  &lt;lastBuildDate&gt; , &lt;/lastBuildDate&gt;
+  &lt;item&gt;<br />   &lt;title&gt;&lt;/title&gt;<br />   &lt;link&gt;&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;&lt;/guid&gt;<br />   &lt;description&gt;&lt;/description&gt;<br />   &lt;pubDate&gt;&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span><span class="highlight">&lt;rss version=&quot;2.0&quot;&gt;
+ &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br /></span>  <span class="highlight">&lt;pubDate&gt; , &lt;/pubDate&gt;<br />  &lt;lastBuildDate&gt; , &lt;/lastBuildDate&gt;
+  &lt;item&gt;<br />   &lt;title&gt;&lt;/title&gt;<br />   &lt;link&gt;&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;&lt;/guid&gt;<br />   &lt;description&gt;&lt;/description&gt;<br />   &lt;pubDate&gt;&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;
+ &lt;/rss&gt;</span></pre></div>
+<div class="textblock">Groups:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; <span class="keyword">print</span> example.item + example.item<br /><span class="stdout">&lt;item&gt;<br />   &lt;title&gt;&lt;/title&gt;<br />   &lt;link&gt;&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;&lt;/guid&gt;<br />   &lt;description&gt;&lt;/description&gt;<br />   &lt;pubDate&gt;&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> </span><span class="highlight">&lt;item&gt;<br />   &lt;title&gt;&lt;/title&gt;<br />   &lt;link&gt;&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;&lt;/guid&gt;<br />   &lt;description&gt;&lt;/description&gt;<br />   &lt;pubDate&gt;&lt;/pubDate&gt;<br />  &lt;/item&gt;</span></pre></div>
+<div class="textblock">Concatenating empty fields produces no output:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; <span class="keyword">print</span> example.item.title + example.item.title<br /></pre>
+</div>
+<div class="textblock">Using the addition operator (<strong>+</strong>) without the assignment operator (<strong>=</strong>) results in a new object. Using
+  the addition and assignment operators together (<strong>+=</strong>) modifies the left-hand object:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.item += example.item<br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate&gt; , &lt;/pubDate&gt;<br />  &lt;lastBuildDate&gt; , &lt;/lastBuildDate&gt;
+  &lt;item&gt;<br />   &lt;title&gt;&lt;/title&gt;<br />   &lt;link&gt;&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;&lt;/guid&gt;<br />   &lt;description&gt;&lt;/description&gt;<br />   &lt;pubDate&gt;&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /></span><span class="highlight">  &lt;item&gt;<br />   &lt;title&gt;&lt;/title&gt;<br />   &lt;link&gt;&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;&lt;/guid&gt;<br />   &lt;description&gt;&lt;/description&gt;<br />   &lt;pubDate&gt;&lt;/pubDate&gt;<br />  &lt;/item&gt;</span><span class="stdout"><br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">Other Template objects or strings can be appended  to a root, field, or group using their<em> append</em> method.</div>
+<div class="textheader"><a id="mul">REPETITION</a></div>
+<div class="textblock">A root, group, or field can be repeated once by calling its <em>repeat</em> method:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.reset()<br />&gt;&gt;&gt; example.item.repeat()<br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate&gt; , &lt;/pubDate&gt;<br />  &lt;lastBuildDate&gt; , &lt;/lastBuildDate&gt;
+  &lt;item&gt;<br />   &lt;title&gt;&lt;/title&gt;<br />   &lt;link&gt;&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;&lt;/guid&gt;<br />   &lt;description&gt;&lt;/description&gt;<br />   &lt;pubDate&gt;&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /></span><span class="highlight">  &lt;item&gt;<br />   &lt;title&gt;&lt;/title&gt;<br />   &lt;link&gt;&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;&lt;/guid&gt;<br />   &lt;description&gt;&lt;/description&gt;<br />   &lt;pubDate&gt;&lt;/pubDate&gt;<br />  &lt;/item&gt;</span><span class="stdout"><br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">A root, group, or field can be repeated more than once by using the multiplication operator, either by itself (<strong>*</strong>),
+  which returns a new object, or along with the assignment operator (<strong>*=</strong>), which modifies the left-hand object:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.reset()<br />&gt;&gt;&gt; example.item *= <span class="int">2</span><br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate&gt; , &lt;/pubDate&gt;<br />  &lt;lastBuildDate&gt; , &lt;/lastBuildDate&gt;
+  &lt;item&gt;<br />   &lt;title&gt;&lt;/title&gt;<br />   &lt;link&gt;&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;&lt;/guid&gt;<br />   &lt;description&gt;&lt;/description&gt;<br />   &lt;pubDate&gt;&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /></span><span class="highlight">  &lt;item&gt;<br />   &lt;title&gt;&lt;/title&gt;<br />   &lt;link&gt;&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;&lt;/guid&gt;<br />   &lt;description&gt;&lt;/description&gt;<br />   &lt;pubDate&gt;&lt;/pubDate&gt;<br />  &lt;/item&gt;</span><span class="stdout"><br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">A root, field, or group can be repeated and have text substituted into it by passing a string, tuple, or dictionary to its <em>repeat</em>
+  method:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.reset()<br />&gt;&gt;&gt; example.item %= (
+... <span class="string">'Example Title: First Example'</span>,
+... <span class="string">'http://www.example.org/rss/5423092'</span>,
+... <span class="string">'http://www.example.org/rss/5423092'</span>,
+... <span class="string">'Example of assigning text to a field.'</span>,
+... <span class="string">'June 06, 2006'</span>)<br />&gt;&gt;&gt; example.item.repeat((
+... <span class="string">'Example Title: Second Example'</span>,
+... <span class="string">'http://www.example.org/rss/5423093'</span>,
+... <span class="string">'http://www.example.org/rss/5423093'</span>,
+... <span class="string">'Example of group repetition.'</span>,
+... <span class="string">'June 06, 2006'</span>))<br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate&gt; , &lt;/pubDate&gt;<br />  &lt;lastBuildDate&gt; , &lt;/lastBuildDate&gt;<br />  &lt;item&gt;<br />   &lt;title&gt;</span><span class="highlight">Example Title: First Example</span><span class="stdout">&lt;/title&gt;<br />   &lt;link&gt;</span><span class="highlight">http://www.example.org/rss/5423092</span><span class="stdout">&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;</span><span class="highlight">http://www.example.org/rss/5423092</span><span class="stdout">&lt;/guid&gt;<br />   &lt;description&gt;</span><span class="highlight">Example of assigning text to a field.</span><span class="stdout">&lt;/description&gt;<br />   &lt;pubDate&gt;</span><span class="highlight">June 06, 2006</span><span class="stdout">&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> </span><span class="highlight">&lt;item&gt;<br />   &lt;title&gt;Example Title: Second Example&lt;/title&gt;<br />   &lt;link&gt;http://www.example.org/rss/5423093&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;http://www.example.org/rss/5423093&lt;/guid&gt;<br />   &lt;description&gt;Example of group repetition.&lt;/description&gt;<br />   &lt;pubDate&gt;June 06, 2006&lt;/pubDate&gt;<br />  &lt;/item&gt;</span><span class="stdout"><br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">A root, field, or group can be expanded to fit a sequence of substitutions by using the power operator (<strong>**</strong>) either alone,
+  which returns a new object, or joined with the assignment operator (<strong>**=</strong>), which modifies the left-hand object:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.reset()<br />&gt;&gt;&gt; example.item **= ((
+... <span class="string">'Example Title: First Example'</span>,
+... <span class="string">'http://www.example.org/rss/5423092'</span>,
+... <span class="string">'http://www.example.org/rss/5423092'</span>,
+... <span class="string">'Example of assigning text to a field.'</span>,
+... <span class="string">'June 06, 2006'</span>), (
+... <span class="string">'Example Title: Second Example'</span>,
+... <span class="string">'http://www.example.org/rss/5423093'</span>,
+... <span class="string">'http://www.example.org/rss/5423093'</span>,
+... <span class="string">'Example of group repetition.'</span>,
+... <span class="string">'June 06, 2006'</span>))<br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate&gt; , &lt;/pubDate&gt;<br />  &lt;lastBuildDate&gt; , &lt;/lastBuildDate&gt;<br />  &lt;item&gt;<br />   &lt;title&gt;</span><span class="highlight">Example Title: First Example</span><span class="stdout">&lt;/title&gt;<br />   &lt;link&gt;</span><span class="highlight">http://www.example.org/rss/5423092</span><span class="stdout">&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;</span><span class="highlight">http://www.example.org/rss/5423092</span><span class="stdout">&lt;/guid&gt;<br />   &lt;description&gt;</span><span class="highlight">Example of assigning text to a field.</span><span class="stdout">&lt;/description&gt;<br />   &lt;pubDate&gt;</span><span class="highlight">June 06, 2006</span><span class="stdout">&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> </span><span class="highlight">&lt;item&gt;<br />   &lt;title&gt;Example Title: Second Example&lt;/title&gt;<br />   &lt;link&gt;http://www.example.org/rss/5423093&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;http://www.example.org/rss/5423093&lt;/guid&gt;<br />   &lt;description&gt;Example of group repetition.&lt;/description&gt;<br />   &lt;pubDate&gt;June 06, 2006&lt;/pubDate&gt;<br />  &lt;/item&gt;</span><span class="stdout"><br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">The number of items in each tuple of substitutions must be equal to the number of fields in the root or group to which it is passed.<br />
+  <br />
+  The maximum number of repetitions  that can be performed on a root, field, or group is controlled by the <em>max</em> property. Assigning a new
+  maximum number of repetitions to the <em>max</em> property assigns the same number to a root or group's child fields or groups. The default value of the <em>max</em>
+  property is 25. Exceeding the maximum repetition value assigned to the <em>max</em> property triggers an exception:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.reset()<br />&gt;&gt;&gt; example.max = <span class="int">1</span><br />&gt;&gt;&gt; example.item **= ((
+... <span class="string">'Example Title: First Example'</span>,
+... <span class="string">'http://www.example.org/rss/5423092'</span>,
+... <span class="string">'http://www.example.org/rss/5423092'</span>,
+... <span class="string">'Example of assigning text to a field.'</span>,
+... <span class="string">'June 06, 2006'</span>), (
+... <span class="string">'Example Title: Second Example'</span>,
+... <span class="string">'http://www.example.org/rss/5423093'</span>,
+... <span class="string">'http://www.example.org/rss/5423093'</span>,
+... <span class="string">'Example of group repetition.'</span>,
+... <span class="string">'June 06, 2006'</span>))<br /><span class="highlight">Traceback (most recent call last):<br />  File &quot;&lt;interactive input&gt;&quot;, line 1, in ?<br />  File &quot;base.py&quot;, line 158, in __ipow__<br />    raise TypeError(_exceptions[0])<br />TypeError: maximum allowed repetitions exceeded</span></pre></div>
+<div class="textblock">Setting the <em>max</em> property to a number greater than 1 allows the operation to be completed successfully.</div>
+<div class="textheader"><a id="iter">ITERATION</a></div>
+<div class="textblock">Performing a loop operation on a root or group iterates over  its    fields or groups in sequence:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; <span class="keyword">for</span> field <span class="keyword">in</span> example: field.__repr__()<br />... <br /><span class="stdout">'&lt;Template &quot;cpubdate&quot; at f62f50&gt;'<br />'&lt;Template &quot;lastbuilddate&quot; at e7a350&gt;'<br />'&lt;Template &quot;item&quot; at f627f0&gt;'</span></pre></div>
+<div class="textheader"><a id="out">OUTPUT</a></div>
+<div class="textblock">The <em>render</em> method is called to output an template as  a string:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; <span class="keyword">print</span> example.render()<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate&gt; , &lt;/pubDate&gt;<br />  &lt;lastBuildDate&gt; , &lt;/lastBuildDate&gt;<br />  &lt;item&gt;<br />   &lt;title&gt;Example Title: First Example&lt;/title&gt;<br />   &lt;link&gt;http://www.example.org/rss/5423092&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;http://www.example.org/rss/5423092&lt;/guid&gt;<br />   &lt;description&gt;Example of assigning text to a field.&lt;/description&gt;<br />   &lt;pubDate&gt;June 06, 2006&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> &lt;item&gt;<br />   &lt;title&gt;Example Title: Second Example&lt;/title&gt;<br />   &lt;link&gt;http://www.example.org/rss/5423093&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;http://www.example.org/rss/5423093&lt;/guid&gt;<br />   &lt;description&gt;Example of group repetition.&lt;/description&gt;<br />   &lt;pubDate&gt;June 06, 2006&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">The <em>write</em> method is called to write a template's string output to a file:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.write(<span class="string">'finalexample.rss'</span>)</pre></div>
+<div class="textblock">The <em>pipe</em> method  outputs  a string  and resets the template  back to its default state:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; <span class="keyword">print</span> example.pipe()<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate&gt; , &lt;/pubDate&gt;<br />  &lt;lastBuildDate&gt; , &lt;/lastBuildDate&gt;<br />  &lt;item&gt;<br />   &lt;title&gt;Example Title: First Example&lt;/title&gt;<br />   &lt;link&gt;http://www.example.org/rss/5423092&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;http://www.example.org/rss/5423092&lt;/guid&gt;<br />   &lt;description&gt;Example of assigning text to a field.&lt;/description&gt;<br />   &lt;pubDate&gt;June 06, 2006&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> &lt;item&gt;<br />   &lt;title&gt;Example Title: Second Example&lt;/title&gt;<br />   &lt;link&gt;http://www.example.org/rss/5423093&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;http://www.example.org/rss/5423093&lt;/guid&gt;<br />   &lt;description&gt;Example of group repetition.&lt;/description&gt;<br />   &lt;pubDate&gt;June 06, 2006&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span><br />&gt;&gt;&gt; <span class="keyword">print</span> example<span class="stdout"><br />&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate&gt; , &lt;/pubDate&gt;<br />  &lt;lastBuildDate&gt; , &lt;/lastBuildDate&gt;
+  &lt;item&gt;<br />   &lt;title&gt;&lt;/title&gt;<br />   &lt;link&gt;&lt;/link&gt;<br />   &lt;guid isPermaLink=&quot;true&quot;&gt;&lt;/guid&gt;<br />   &lt;description&gt;&lt;/description&gt;<br />   &lt;pubDate&gt;&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<p>
+<a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-xhtml11" alt="Valid XHTML 1.1" height="31" width="88" /></a>
+</p>
+<div class="footer">Copyright 2007 L. C. Rees. All rights reserved.</div>
+</body>
+</html>

File webstring/docs/webstring.css

+.headertext {
+	font-family: Georgia, "Times New Roman", Times, serif;
+	font-size: 24px;
+	vertical-align: middle;
+	text-align: right;
+	display: block;
+}
+.header {
+	border: medium solid #000000;
+	height: 230px;
+	width: 700px;
+	left: 5px;
+	top: 5px;
+	margin: 5px;
+	padding: 5px;
+}
+.headerimg {
+	text-align: left;
+	display: block;
+}
+.textheader {
+	border-top-width: thin;
+	border-right-width: thin;
+	border-bottom-width: thin;
+	border-left-width: thin;
+	border-top-style: none;
+	border-right-style: none;
+	border-bottom-style: dashed;
+	border-left-style: none;
+	border-top-color: #000000;
+	border-right-color: #000000;
+	border-bottom-color: #000000;
+	border-left-color: #000000;
+	font-family: Verdana, Arial, Helvetica, sans-serif;
+	font-size: 16px;
+	font-weight: bold;
+	color: #000000;
+	padding: 15px 5px 5px;
+	height: 10px;
+	width: 700px;
+	text-align: left;
+	margin: 10px;
+}
+.textblock {
+	font-family: Verdana, Arial, Helvetica, sans-serif;
+	font-size: 14px;
+	font-style: normal;
+	font-weight: normal;
+	color: #000000;
+	text-decoration: none;
+	margin: 5px;
+	padding: 5px;
+	width: 700px;
+}
+em {
+	font-family: Verdana, Arial, Helvetica, sans-serif;
+	font-style: italic;
+
+}
+
+a {
+	text-decoration: none;
+}
+a:hover {
+	text-decoration: underline;
+}
+strong {
+	font-weight: bold;
+}
+.codeblock {
+	background-color: #FBFAE3;
+	white-space: pre;
+	font-family: "Courier New", Courier, mono;
+	margin: 5px;
+	padding: 5px 10px 5px 5px;
+	width: 690px;
+	overflow: auto;
+	border-right: thin;
+	border-bottom: thin;
+	border-left: thin;
+	font-weight: normal;
+}
+
+pre {
+	font-family: "Courier New", Courier, mono;
+	font-size: 14px;
+	margin: 0px;
+	padding: 0px;
+}
+
+.toc {
+	font-family: Verdana, Arial, Helvetica, sans-serif;
+	font-size: 16px;
+	width: 200px;
+	left: 730px;
+	top: 5px;
+	margin: 5px;
+	padding: 5px;
+	color: #000000;
+	border: thin solid #000000;
+	position: absolute;
+}
+
+.entry {
+	margin: 3px;
+	padding: 3px;
+}
+
+.footer {
+	font-family: Arial, Helvetica, sans-serif;
+	font-size: 9px;
+	color: #999999;
+}
+
+img {
+	border: 0px;
+}
+.string {
+	color: #999900;
+	font-weight: bold;
+
+
+}
+.stdout {
+	color: #408080;
+
+}
+.highlight {
+	color: #FF0000;
+	font-weight: bold;
+
+}
+.keyword {
+	font-weight: bold;
+	color: #000099;
+}
+.int {
+	color: cyan;
+	font-weight: bold;
+
+}

File webstring/docs/webstring.gif

Added
New image

File webstring/docs/webstring.html

+<?xml version="1.0" encoding="utf-8"?>
+<?xml-stylesheet href="webstring.css" type="text/css" media="screen" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>webstring: A Python Template Engine</title>
+<link href="webstring.css" rel="stylesheet" type="text/css" media="screen" />
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+</head>
+<body>
+<div class="toc">
+<div class="entry"><a href="#whatisit">What is it?</a></div>
+<div class="entry"><a href="#license">License</a></div>
+<div class="entry"><a href="#download">Download</a></div>
+<div class="entry"><a href="#installation">Installation</a></div>
+<div class="entry"><a href="#requirements">Requirements</a></div>
+<div class="entry"><a href="#classes">Classes</a></div>
+<div class="entry"><a href="#initialization">Initialization</a></div>
+<div class="entry"><a href="#objects">Objects</a></div>
+<div class="entry"><a href="#dataaccess">Access</a></div>
+<div class="entry"><a href="#sub">Substitution</a></div>
+<div class="entry"><a href="#attr">Attributes</a></div>
+<div class="entry"><a href="#batch">Batch Substitution</a></div>
+<div class="entry"><a href="#state">State</a></div>
+<div class="entry"><a href="#add">Concatenation </a></div>
+<div class="entry"><a href="#mul">Repetition</a></div>
+<div class="entry"><a href="#append">Appending</a></div>
+<div class="entry"><a href="#iter">Iteration</a></div>
+<div class="entry"><a href="#out">Output</a></div>
+<div class="entry"><a href="#dev">Development</a></div>
+</div>
+<div class="header"><img class="headerimg" src="webstring.gif" width="400" height="201" alt="webstring" />
+  <div class="headertext">A Python Template Engine</div>
+</div>
+<div class="textheader"><a id="whatisit">WHAT IS IT?</a></div>
+<div class="textblock">
+<em>webstring</em> is a template engine for programmers 
+  whose favorite template language is <a href="http://www.python.org/">Python</a>. <em>webstring </em>can be used to generate any text output from a template with the additional advantages of advanced XML and HTML templating using the lxml and cElementTree libraries.
+  <em><br />
+  <br />
+    webstring </em>was designed to meet the following general goals:  
+  <ol>
+    <li><strong>To separate model and view logic from controller logic.</strong> 
+The advantages of using an MVC architecture are:<br />
+      <ul>
+        <li><strong>Clarity:</strong> it is easy to tell which parts of an application do what. Code is  clearer, more compact, and readable, 
+    which can make errors easier to spot, a  particularly important feature when 
+    more than one developer maintains the code.</li>
+        <li><strong>Modularity:</strong> model, view, or controller logic can be upgraded, reused, or replaced 
+    with little or no disruption to other parts of an application if they are 
+    not mixed together.</li>
+        <li>
+    <strong>Division of Labor:</strong> designers should design the view, programmers should 
+    program the controller, and data architects should design the model.</li>
+      </ul>
+      <br />
+	  <em>webstring </em>enforces MVC 
+    by following a pipeline or push template style: Python controller code has to explicitly 
+    push data into the template because a <em>webstring</em> template contains no callback 
+    logic and therefore cannot  itself request data from the controller.<br />
+          </li>
+    <li>
+<strong>To separate template logic from template data.</strong> Template data is text in the 
+    template that does not originate from an external source. Template logic controls 
+    a template's output when when template data and external data are mixed. Template 
+    data tells what a template is and template logic tells how it works. 
+            The advantages 
+    of keeping template data distinct from template logic are similar to the advantages 
+    of using an MVC architecture:<br />
+      <ul>
+        <li><strong>Clarity:</strong>  mental clarity is 
+    easily achieved when template data and template logic are encapsulated in 
+    separate, clearly distinct packages. webstring allows    template 
+    data to be kept in one file and  Python code, its  template logic, in another. 
+    Text data and logic are fundamentally different beasts: Text data is generally  a declarative data 
+    format that defines what  should be computed. Python is an imperative format that defines how computation 
+    should be performed. Separating them is the road to easier maintenance.</li>
+        <li><strong>Modularity:</strong> modular template data and template logic can be upgraded, reused, 
+    or replaced with little or no disruption to each other. <em>webstring</em>'s  placeholders are non-invasive markers. Many template engines use some kind 
+    of explicit or implicit logic for placeholders. This is not a modular approach: 
+    it sharply intertwines not only template logic and data but model, view, and 
+    controller logic. <em>webstring</em> keeps template data and template logic separate. Template logic does not have to know anything about 
+    the text half of a <em>webstring</em> template except for the name of its placeholders. 
+    Template data can be written without any structural awareness that it will 
+    ever be template data, let alone by controlled by external template logic 
+    written in Python. All it needs are placeholders that identify where external data can be inserted.</li>
+        <li><strong>Division of labor:</strong> separating template data from template logic allows for 
+    a clean separation of roles: Data architects can design text formats, designers 
+    can work on making text look good, and Python programmers can write 
+    controller code.<br />
+        </li>
+      </ul>
+    </li>
+    <li>
+<strong>To require only Python for templating.</strong> When templating   with Python, the minimum requirement is, of course, 
+    Python. <em>webstring</em> goes further: its design is based on the proposition 
+    that the <em>only</em> tool you need to template text with  Python is  Python.<br />
+      <br />
+             
+    Many template engines use a custom template language, usually with just enough 
+    logic to handle variable substitution, condition statements, and loops. Compared with the effort of templating  with C or Java, using a 
+    custom template language can be a giant step forward in programmer productivity. 
+    Using a custom template language with Python, however, is a giant step backwards.<br />
+      <br />
+    By design, Python places programmer productivity ahead of computer productivity, 
+    an approach that Bruce Eckel nicely summarized as  “Python fits your brain”. 
+    The average Python programmer can keep the core Python language in their head 
+    without constantly checking Python's documentation for information on basic 
+    language features. Layering another language on top of Python increases the 
+    mental overhead of programming with few compensating advantages. Why use a 
+    special purpose template language when the general purpose programming language 
+    you already know  does the job?<br />
+       </li>
+    <li>
+<strong>To use Python syntax, idiom, and patterns.</strong> The reason for this design goal is similar to the reason behind  goal number three: if a programmer 
+    has already invested the time to learn Python, why devalue that investment 
+    by introducing syntax, idioms, or patterns that are not &quot;Pythonic&quot; into Python templating?<br />
+      <br />
+             <em>webstring</em> uses Python syntax, idiom, and patterns exclusively. Template placeholders  are mapped to Python objects. These 
+    objects implement portions of Python's <a href="http://docs.python.org/lib/typesseq.html">sequence API</a> and support operations like 
+    access by position, concatenation, and repetition. They can also be manipulated 
+    like Python strings.
+    If a <em>webstring</em> operation has an exact analog in existing 
+    Python usage, the Python analog was used. Where no exact one-to-one analog 
+    exists, names of methods and attributes from the Python standard library and 
+    third-party modules where the usage approaches <em>webstring's</em> were used. <br />
+      <br />
+            Making 
+    methods as Pythonic as possible was a major emphasis of <em>webstring's</em> development. 
+    Use <em>webstring</em> should be painless for a Python programmer; its 
+    usage should be a direct and natural outgrowth of their previous Python experience.<br />
+    </li>
+    <li><strong>To play well with other Python software.</strong> <em>webstring</em> is designed to be imported into another piece of Python software 
+    and used without much modification or complexity. Its API is Pythonic and 
+    many of its operations use standard Python syntax. All data inputs into <em>webstring</em> 
+    use standard Python data structures like strings, lists, and dictionaries.<br />
+      <br />
+    <em>webstring</em> provides classes that implement the Python <a href="http://www.python.org/dev/peps/pep-0333/">Web Server Gateway 
+    Interface</a> (WSGI) standard that provides a common way for Python web applications 
+    to run on different web servers. These classes, WSGITemplate,  WSGIHTMLTemplate, 
+    and WSGITextTemplate, are WSGI middleware that allows WSGI-compliant Python web applications 
+    to dynamically output XML,  HTML, and text.<br />
+      <br />
+      <em>webstring </em>also includes a class, TurboWebstring, that implements the TurboGears/Buffet <a href="http://www.turbogears.org/docs/plugins/template.html">template plugin API</a>.</li>
+  </ol>
+	
+  <em>webstring's </em>XML and HTML templating was designed to meet the following goals:
+    
+  <ol>
+    <li><strong>To use XML as a data format, not a programming language.</strong> XML has several disadvantages as a programming language. First of all, it 
+    was never intended to be a programming language. Tim Berners-Lee, creator 
+    of HTML and a driving force behind the standardization of XML, commented on HTML and, by implication, on XML that, &quot;I chose HTML not to be a programming language because I wanted different 
+    programs to do different things with it: present it differently, extract tables 
+    of contents, index it, and so on.&quot; It  must also be structured in ways that, while useful for a data format, 
+    are unnecessarily verbose, restrictive, and repetitive for a programming language, 
+    especially if the programming language is Python. 
+      <p> XML is   also frequently worked on by non-programmers. Mixing logic  and XML may force non-programmers to acquire a programming awareness that may be counterproductive 
+    to their jobs. They  might also be forced to wait for a programmer to 
+    change the data format before they can work on it (and vice versa). <br />
+        <br />
+XML is for data. Python is for logic.</p>
+    </li>
+    <li><strong>To use existing XML formats.</strong> Many template engines use custom XML syntax for placeholders, usually either 
+    custom comments, elements, or attributes. Existing XML formats must often 
+    include this template engine specific XML to work with these template engines. 
+    This can violate the MVC advantages of clarity, modularity, and division of 
+    labor. It can make using outside software that provides special processing 
+    for a specific XML format more difficult. It can lead to template engine 
+    lock-in since prohibitively extensive modifications may be required to move 
+    an XML template from one template engine to another.<br />
+      <br />
+    <em>webstring</em> is designed to work with existing XML formats as they are. The only 
+    modifications to an XML document that <em>webstring</em> requires is assigning a unique 
+    identifier to each element used as a placeholder. <em>webstring</em> can use any XML 
+    attribute as a placeholder but, by default, it uses the ID attribute. This 
+    closely follows the spirit of the W3C <a href="http://www.w3.org/TR/xml-id/">xml:id</a> standard which makes the ID attribute 
+    the standard mechanism for uniquely identifying elements within an XML document.<br />
+       
+    </li>
+    <li><strong>To hide the parts of an XML document that are not being used.</strong> <em>
+    webstring</em>  uses a <a href="http://www.phpwact.org/pattern/template_view#component_apis">component API</a> style: it only exposes elements that 
+    are marked with a placeholder and usually only &quot;the elements in the template 
+    that need to be manipulated are marked&quot;. Each element marked with a placeholder 
+    can be accessed, evaluated, and manipulated separately. Elements and attributes 
+    that do not have a placeholder remain hidden and  do not exist from the programmer or application's perspective.<br />
+ </li>
+    <li>
+<strong>To use the best Python XML libraries.</strong> <a href="http://effbot.org/zone/celementtree.htm">cElementTree</a>  provides a high performance library with a highly Pythonic 
+    API for processing XML with Python. 
+    <a href="http://codespeak.net/lxml/">lxml</a> implements the same API as cElementTree 
+    but adds additional features. While cElementTree supports 
+    most of the XML 1.1 standard, XML namespaces, and parts of the XPath 1.0 standard, 
+    lxml, since it's a binding for the <a href="http://xmlsoft.org/">libxml2 and libxslt libraries</a>, supports 
+    those standards plus XSLT, XInclude, XML Schema, RelaxNG, Xpointer, and xml:id. 
+    Since libxml2 and libxslt are written in C, lxml's performance approaches 
+    that of cElementTree.<br />
+      <br />
+    <em>webstring</em> does not force its users to pick between best of breed Python XML 
+    processing libraries. They can use the library that best fits their needs 
+    while using the same simple yet powerful API.<br />
+    </li>
+    <li>To bridge HTML and XML.
+XML purists would like to leave HTML behind. But they can't. To quote the<a href="http://www.kid-templating.org/trac/wiki/KidFaq#but-isn-t-tag-soup-like-html-4-evil"> Kid FAQ</a>:
+      <blockquote>
+        <p><em>Q: But isn't tag-soup like HTML 4 evil?<br />
+    <br />
+    A: No. HTML 4.01 isn't XML but it's the best option for serving pages at present 
+    because all browsers have relatively strong support for it. Serving XHTML as text/html has serious issues and not all browsers (IE &lt;= 7.0) support XHTML as application/xhtml+xml. </em>
+        </p>
+        <p><em>However, maintaining content in an XML based format is advantageous because you can 
+    perform validation, transformations, and other stuff using readily available 
+    tools. It's possible to have the best of both worlds: HTML 4.01 for the browser 
+    and XHTML (or some custom XML format) for the server.</em></p>
+        <p><em>Some of us still believe 
+    that XHTML will eventually be supported well, and that when it does, it will 
+    be the way to go. You should be able to &quot;flip a switch, make it work&quot; 
+    when that day comes instead of doing a massive migration</em>.</p>
+      </blockquote>
+      <p> <em>webstring's</em> HTMLTemplate class handles these cases. It can take HTML, even 
+    if it is horribly broken, transform it into valid XHTML, and correctly output 
+    it as HTML 4.01, XHTML 1.0, or XHTML 1.1 following the standard and practice 
+    of the W3C.</p>
+    </li>
+  </ol
+    1. To separate model and view logic from controller logic. >
+</div>
+<div class="textheader"><a id="license">LICENSE</a></div>
+<div class="textblock"><em>webstring</em> is distributed under a <a href="http://www.opensource.org/licenses/bsd-license.php">BSD 
+  license</a>.</div>
+<div class="textheader"><a id="download">DOWNLOAD</a></div>
+<div class="textblock"> <em>webstring</em> is available from the <a href="http://cheeseshop.python.org/pypi/webstring/">CheeseShop</a> 
+  as a: 
+  <ul>
+    <li> Windows <a href="http://cheeseshop.python.org/packages/source/w/webstring/webstring-0.5.zip">source 
+      package</a> (zipfile)</li>
+    <li> Windows <a href="http://cheeseshop.python.org/packages/source/w/webstring/webstring-0.5.win32.exe">binary 
+      installer</a></li>
+    <li> UNIX <a href="http://cheeseshop.python.org/packages/source/w/webstring/webstring-0.5.tar.gz">source 
+      package</a> (gzipped tarball)</li>
+    <li>UNIX <a href="http://cheeseshop.python.org/packages/source/w/webstring/webstring-0.5.tar.bz2">source 
+      package</a> (bzipped tarball)</li>
+    <li><a href="http://cheeseshop.python.org/packages/2.4/w/webstring/webstring-0.5-py2.4.egg">Python 
+      2.4 Egg</a></li>
+    <li><a href="http://cheeseshop.python.org/packages/2.5/w/webstring/webstring-0.5-py2.5.egg">Python 
+      2.5 Egg</a></li>
+  </ul>
+  <em>webstring's</em> current release is 0.5 (1.4.2007). The change log for 0.5 
+  is available here: <a href="http://psilib.sourceforge.net/changelog-0.5">CHANGELOG-0.5</a>.<br />
+<br />
+  <em>lwebstring</em> was a standalone <a href="http://codespeak.net/lxml/">lxml</a>-based 
+  implementation of <em>webstring</em> available from the <a href="http://cheeseshop.python.org/pypi/lwebstring/">CheeseShop</a> 
+  as a:
+<ul>
+    <li> Windows <a href="http://cheeseshop.python.org/packages/source/l/lwebstring/lwebstring-0.5.zip">source 
+      package</a> (zipfile)</li>
+    <li> Windows <a href="http://cheeseshop.python.org/packages/2.4/l/lwebstring/lwebstring-0.5.win32.exe">binary 
+      installer</a></li>
+    <li> UNIX <a href="http://cheeseshop.python.org/packages/source/l/lwebstring/lwebstring-0.5.tar.gz">source 
+      package</a> (gzipped tarball)</li>
+    <li>UNIX <a href="http://cheeseshop.python.org/packages/source/l/lwebstring/lwebstring-0.5.tar.bz2">source 
+      package</a> (bzipped tarball)</li>
+    <li><a href="http://cheeseshop.python.org/packages/2.4/l/lwebstring/lwebstring-0.5-py2.4.egg">Python 
+      Egg</a></li>
+  </ul>
+  The last <em>lwebstring </em> release was 0.5 (10.5.2006). After this release, 
+  <em>lwebstring</em> was incorporated into <em>webstring</em> proper<em>. </em>The 
+  change log for <em>lwebstring</em> 0.5 is available here: <a href="http://psilib.sourceforge.net/CHANGELOG-lwebstring-0.5">CHANGELOG-lwebstring-0.5</a>.</div>
+<div class="textheader"><a id="installation">INSTALLATION</a></div>
+<div class="textblock">To install <em>webstring</em>  using <em><a href="http://peak.telecommunity.com/DevCenter/EasyInstall">easy_install</a>, </em>
+ run the following   command with administrative privileges:</div>
+<div class="codeblock"><pre>easy_install webstring</pre></div>
+<div class="textheader"><a id="requirements">REQUIREMENTS</a></div>
+<div class="textblock"><em>webstring</em> requires <a href="http://effbot.org/downloads/#cElementTree">cElementTree</a>, 
+    <a href="http://effbot.org/downloads/#elementtree">elementtree</a>, and <a href="http://codespeak.net/lxml/">lxml</a>. 
+    <em>webstring</em> can use either cElementTree or lxml as its XML processing 
+    library. Installing <em>webstring</em> with <em><a href="http://peak.telecommunity.com/DevCenter/EasyInstall">easy_install</a></em> 
+    automatically downloads and installs cElementTree, elementtree, and lxml if 
+    necessary along with <em>webstring</em>.<br />
+	<br />
+  <a href="http://effbot.org/downloads/#elementtidy">elementtidy</a> is required 
+    for <em>webstring's</em> <em>HTMLTemplate</em> class if you need to handle 
+    broken HTML with cElementTree.<br />
+    <br />
+    <em>webstring</em> has been tested and verified to work with <a href="http://www.python.org/download/releases/2.4/">Python 
+    2.4</a> and <a href="http://www.python.org/download/releases/2.5/">Python 
+    2.5</a>.</p>
+</div>
+<div class="textheader"><a id="classes">CLASSES</a></div>
+  
+<div class="textblock"><em>webstring</em> comes with the following specialized 
+  classes: 
+  <ul>
+    <li>XmlTemplate is a frontend for <em>webstring's</em> XML templating 
+      classes.</li>
+    <li>EtreeTemplate is an XML template class that uses cElementTree 
+      as its XML processing library.</li>
+    <li>LxmlTemplate is an XML template class that uses lxml as its XML 
+      processing library.</li>
+    <li>TextTemplate is a general purpose text templating class. A tutorial 
+      for <em>webstring's</em> text templating is available <a href="text.html">here</a>.</li>
+    <li>HTMLTemplate provides HTML templating plus HTML-specific tasks 
+      like cleaning up broken HTML and outputting correct (X)HTML.</li>
+  </ul>
+These classes can be used individually or accessed through <em>webstring's </em>Template 
+  class, which acts as a general purpose frontend to all of <em>webstring's</em> specialized 
+  classes. </div>
+<div class="codeblock"><pre>&gt;&gt;&gt; <span class="keyword">from</span> webstring <span class="keyword">import</span> Template</pre></div>
+<div class="textblock">The remaining examples in this document use <em>webstring's </em>XmlTemplate as the backend to Template. LxmlTemplate and EtreeTemplate 
+have minor differences in output. In LxmlTemplate, there is no space between the tag name and the closing /&gt; of a closed tag 
+(i.e. &lt;br/&gt; instead of &lt;br /&gt;) and in EtreeTemplate there is a space. Attribute order may also vary and namespaces may 
+be handled differently.</div>
+<div class="textheader"><a id="initialization">INITIALIZATION</a></div>
+<div class="textblock">A Template object can be initialized empty:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; exampleA = Template()</pre></div>
+<div class="textblock">From a file with the <em>fromfile</em> method:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; exampleB.fromfile(<span class="string">'example.rss'</span>)</pre></div>
+<div class="textblock">By passing the path to the file as the first argument to the class constructor:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; exampleC = Template(<span class="string">'example.rss'</span>)</pre></div>
+<div class="textblock">From a string with the <em>fromstring</em> method:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; exampleD = Template.fromstring(<span class="string">&quot;&quot;&quot;&lt;rss version=&quot;2.0&quot;&gt;</span><br />...  <span class="string">&lt;channel&gt;</span><br />...   <span class="string">&lt;title&gt;Example&lt;/title&gt;</span><br />...   <span class="string">&lt;link&gt;http://www.example.org/&lt;/link&gt;</span><br />...   <span class="string">&lt;description&gt;RSS Example&lt;/description&gt;</span><br />...   <span class="string">&lt;language&gt;en-us&lt;/language&gt;</span><br />...   <span class="string">&lt;pubDate id=&quot;cpubdate&quot;&gt;$month $day, $year&lt;/pubDate&gt;</span><br />...   <span class="string">&lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;%(month)s %(day)s, %(year)s&lt;/lastBuildDate&gt;</span>
+...   <span class="string">&lt;item class=&quot;item&quot;&gt;</span><br />...    <span class="string">&lt;title id=&quot;title&quot; /&gt;</span><br />...    <span class="string">&lt;link id=&quot;link&quot; /&gt;</span><br />...    <span class="string">&lt;guid id=&quot;guid&quot; isPermaLink=&quot;true&quot; /&gt;</span><br />...    <span class="string">&lt;description id=&quot;description&quot; /&gt;</span><br />...    <span class="string">&lt;pubDate id=&quot;ipubdate&quot; /&gt;</span><br />...   <span class="string">&lt;/item&gt;</span><br />...  <span class="string">&lt;/channel&gt;</span><br />...  <span class="string">&lt;/rss&gt;&quot;&quot;&quot;</span>)</pre></div>
+<div class="textblock">By passing a string as  the first argument  to the class constructor:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example = Template(<span class="string">&quot;&quot;&quot;&lt;rss version=&quot;2.0&quot;&gt;</span><br />...  <span class="string">&lt;channel&gt;</span><br />...   <span class="string">&lt;title&gt;Example&lt;/title&gt;</span><br />...   <span class="string">&lt;link&gt;http://www.example.org/&lt;/link&gt;</span><br />...   <span class="string">&lt;description&gt;RSS Example&lt;/description&gt;</span><br />...   <span class="string">&lt;language&gt;en-us&lt;/language&gt;</span><br />...   <span class="string">&lt;pubDate id=&quot;cpubdate&quot;&gt;$month $day, $year&lt;/pubDate&gt;</span><br />...   <span class="string">&lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;%(month)s %(day)s, %(year)s&lt;/lastBuildDate&gt;</span>
+...   <span class="string">&lt;item class=&quot;item&quot;&gt;</span><br />...    <span class="string">&lt;title id=&quot;title&quot; /&gt;</span><br />...    <span class="string">&lt;link id=&quot;link&quot; /&gt;</span><br />...    <span class="string">&lt;guid id=&quot;guid&quot; isPermaLink=&quot;true&quot; /&gt;</span><br />...    <span class="string">&lt;description id=&quot;description&quot; /&gt;</span><br />...    <span class="string">&lt;pubDate id=&quot;ipubdate&quot; /&gt;</span><br />...   <span class="string">&lt;/item&gt;</span><br />...  <span class="string">&lt;/channel&gt;</span><br />...  <span class="string">&lt;/rss&gt;&quot;&quot;&quot;</span>)</pre></div>
+<div class="textblock">The choice of whether to use lxml and <em>LxmlTemplate</em> 
+  or cElementTree and <em>EtreeTemplate</em> is controlled by using the <em>engine</em> 
+  keyword passed to the object constructor:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example = Template(engine="lxml")</pre></div>
+<div class="textblock">This selects <em>LxmlTemplate</em> and uses lxml as the 
+  XML processing library. LxmlTemplate and lxml support additional advanced XML 
+  features like <a href="http://www.w3.org/tr/xslt">XSLT</a> and <a href="http://www.w3.org/TR/xinclude/">XInclude</a> 
+  that EtreeTemplate and cElementTree do not.<br />
+  <br />
+  <em>HTMLTemplate</em> can be selected using the <em>format</em> keyword passed 
+  to the object constructor:</div>
+  <div class="codeblock"><pre>&gt;&gt;&gt; example = Template(format="html", engine="lxml")</pre></div>
+<div class="textblock"><em>HTMLTemplate</em> can also be told to use lxml as its HTML 
+  processing library by passing the <em>engine</em> keyword together with the 
+  <em>format</em> keyword to the object constructor:</div>
+    <div class="codeblock"><pre>&gt;&gt;&gt; example = Template(format="html", engine="lxml")</pre></div>	    
+<div class="textheader"><a id="objects">OBJECTS</a></div>
+<div class="textblock"><em>webstring</em>  automatically maps an XML document to a root object. Any XML element with an XML attribute (by default, <strong><a href="http://www.w3.org/TR/xml-id/">id</a></strong>)
+  that uniquely identifies it within an XML document is  mapped to a field object and attached to the  root object of its  parent document.</div>
+<div class="codeblock"><pre class="stdout">&lt;pubDate <span class="highlight">id=&quot;cpubdate&quot;</span>&gt;$month $day, $year&lt;/pubDate&gt;</pre></div>
+<div class="textblock">Groups of fields can be created  by assigning a parent element an attribute (by default, <strong>class</strong>) whose value   is a globally unique identifier  within an XML document.
+  <em>webstring</em>  then maps the parent element to a group object which is attached  to the root object of its parent document. Any child elements marked as fields within that parent element are mapped to field objects and  attached to the group object.<br />
+<br />
+Group objects cannot contain other group objects.</div>
+<div class="codeblock"><pre class="stdout">&lt;item <span class="highlight">class=&quot;item&quot;</span>&gt;<br /> &lt;title id=&quot;title&quot; /&gt;<br /> &lt;link id=&quot;link&quot; /&gt;<br /> &lt;guid id=&quot;guid&quot; isPermaLink=&quot;true&quot; /&gt;<br /> &lt;description id=&quot;description&quot; /&gt;<br /> &lt;pubDate id=&quot;ipubdate&quot; /&gt;<br />&lt;/item&gt;</pre></div>
+<div class="textblock">XML attributes of an element marked as a field are mapped to attribute objects and attached to that element's field
+    object.<br />
+<br />At maximum, a root's object hierarchy will never be more than four levels deep.<br /><br />Root level:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example<br /><span class="stdout">&lt;Template &quot;root&quot; at db7dd0&gt;</span></pre></div>
+<div class="textblock">Group level:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.item<br /><span class="stdout">&lt;Template &quot;item&quot; at f5d870&gt;</span></pre></div>
+<div class="textblock">Field level:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.item.guid<br /><span class="stdout">&lt;Template &quot;guid&quot; at f5da70&gt;</span></pre></div>
+<div class="textblock">Attribute level:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.item.guid.isPermaLink<br /><span class="stdout">'true'</span></pre></div>
+<div class="textblock">At minimum, a root object's depth will only be two levels deep.<br /><br />Root level:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example<br /><span class="stdout">&lt;Template &quot;root&quot; at db7dd0&gt;</span></pre></div>
+<div class="textblock">Field level:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.cpubdate<br /><span class="stdout">&lt;Template &quot;cpubdate&quot; at e7a350&gt;</span></pre></div>
+<div class="textblock">By default, all elements tagged as fields or groups become
+  part of a root's object hierarchy except for elements marked  as groups that have  no  child elements marked as fields. However,
+  existing fields or groups within an XML document can be excluded or included before or after a root is initialized by using its <em>exclude</em> or <em>include</em> methods.<br />
+  <br />
+  Exclusion with the <em>exclude</em> method:</div>
+  <div class="codeblock"><pre>&gt;&gt;&gt; example.exclude(<span class="string">'cpubdate'</span>, <span class="string">'guid'</span>) <br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;%(month)s %(day)s, %(year)s&lt;/lastBuildDate&gt;<br />  &lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot; /&gt;<br />   &lt;link id=&quot;link&quot; /&gt;<br />   &lt;description id=&quot;description&quot; /&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot; /&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">Inclusion with the <em>include</em> method:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.include(<span class="string">'cpubdate'</span>, <span class="string">'guid'</span>)<br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  </span><span class="highlight">&lt;pubDate id=&quot;cpubdate&quot;&gt;$month $day, $year&lt;/pubDate&gt;</span><span class="stdout"><br />  &lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;%(month)s %(day)s, %(year)s&lt;/lastBuildDate&gt;
+  &lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot; /&gt;<br />   &lt;link id=&quot;link&quot; /&gt;<br />   </span><span class="highlight">&lt;guid id=&quot;guid&quot; isPermaLink=&quot;true&quot; /&gt;</span><span class="stdout"><br />   &lt;description id=&quot;description&quot; /&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot; /&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">Fields and groups can  be removed by deleting
+  their object attribute:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; <span class="keyword">del</span> example.cpubdate<br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;%(month)s %(day)s, %(year)s&lt;/lastBuildDate&gt;<br />  &lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot; /&gt;<br />   &lt;link id=&quot;link&quot; /&gt;<br />   &lt;guid id=&quot;guid&quot; isPermaLink=&quot;true&quot; /&gt;<br />   &lt;description id=&quot;description&quot; /&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot; /&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">A root, field, or group can be set back to its default state by calling
+  its <em>reset</em> method:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.reset()<br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate id=&quot;cpubdate&quot;&gt;$month $day, $year&lt;/pubDate&gt;<br />  &lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;%(month)s %(day)s, %(year)s&lt;/lastBuildDate&gt;<br />  &lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot; /&gt;<br />   &lt;link id=&quot;link&quot; /&gt;<br />   &lt;guid id=&quot;guid&quot; isPermaLink=&quot;true&quot; /&gt;<br />   &lt;description id=&quot;description&quot; /&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot; /&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textheader"><a id="dataaccess">ACCESS</a></div>
+<div class="textblock">Fields can be accessed by object attribute:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.cpubdate<br /><span class="stdout">&lt;Template &quot;cpubdate&quot; at e7a350&gt;</span></pre></div>
+<div class="textblock">By keyword:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example[<span class="string">'cpubdate'</span>]<br /><span class="stdout">&lt;Template &quot;cpubdate&quot; at e7a350&gt;</span></pre></div>
+<div class="textblock">By position:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example[<span class="int">0</span>]<br /><span class="stdout">&lt;Template &quot;cpubdate&quot; at e7a350&gt;</span></pre></div>
+<div class="textblock">Groups are accessed the same way:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.item <br /><span class="stdout">&lt;Template &quot;item&quot; at f5d870&gt;</span><br />&gt;&gt;&gt; example[<span class="string">'item'</span>]<br /><span class="stdout">&lt;Template &quot;item&quot; at f5d870&gt;</span><br />&gt;&gt;&gt; example[<span class="int">2</span>]<br /><span class="stdout">&lt;Template &quot;item&quot; at f5d870&gt;</span></pre></div>
+<div class="textblock">Fields within a group are accessed by combining its identifier and  its group identifier:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.item.title <br /><span class="stdout">&lt;Template &quot;title&quot; at f5d9b0&gt;</span><br />&gt;&gt;&gt; example[<span class="string">'item'</span>][<span class="string">'title'</span>]<br /><span class="stdout">&lt;Template &quot;title&quot; at f5d9b0&gt;</span><br />&gt;&gt;&gt; example[<span class="int">2</span>][<span class="int">0</span>]<br /><span class="stdout">&lt;Template &quot;title&quot; at f5d9b0&gt;</span></pre></div>
+<div class="textblock">Attributes can be accessed either by object attribute or by keyword:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.item.guid.isPermaLink<br /><span class="stdout">'true'</span><br />&gt;&gt;&gt; example[<span class="string">'item'</span>][<span class="string">'guid'</span>][<span class="string">'isPermaLink'</span>]<br /><span class="stdout">'true'</span></pre></div>
+<div class="textblock">By default, <em>webstring</em> automatically maps fields, groups, and attributes to object attributes with the same name as the field, group, or attribute's identifier. This &quot;auto-magical&quot; behavior can be disabled by passing a boolean value of <span class="keyword">False</span> to the class constructor  as the second argument when a Template or HTMLTemplate object is initialized:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; exampleZ = Template(<span class="string">'example.rss', </span><span class="keyword">False</span>)</pre></div>
+<div class="textblock">Fields, groups, and attributes can   then be accessed by keyword or  position  but not by named object attribute.</div>
+<div class="textheader"><a id="sub">SUBSTITUTION</a></div>
+<div class="textblock">Text can be substituted into a field by assigning a string to a field's text property:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.item.description.text = <span class="string">'Example of assigning text to a field.'</span>
+&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate id=&quot;cpubdate&quot;&gt;June 06, 2006&lt;/pubDate&gt;<br />  &lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;June 06, 2006&lt;/lastBuildDate&gt;<br />  &lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot; /&gt;<br />   &lt;link id=&quot;link&quot; /&gt;<br />   &lt;guid id=&quot;guid&quot; isPermaLink=&quot;true&quot; /&gt;<br />   &lt;description id=&quot;description&quot;&gt;</span><span class="highlight">Example of assigning text to a field.</span><span class="stdout">&lt;/description&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot; /&gt;<br />  &lt;/item&gt;<br />  &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">Text can also be formatted by substituting text into a field's string template. There are two ways to assign a string template to a field.
+  The first way is to embed a string template directly in the XML source:</div>
+<div class="codeblock"><pre class="stdout">&lt;pubDate id=&quot;cpubdate&quot;&gt;<span class="highlight">$month $day, $year</span>&lt;/pubDate&gt;</pre></div>
+<div class="textblock">This string template follows the pattern used by Python's <a href="http://docs.python.org/lib/node109.html"><em>string.Template</em></a>
+  class where <strong>$</strong> identifies a location (e.g. <span class="highlight">$month</span>) where strings can be substituted into a template to make a new string. A field's
+  template is used to format its text when a dictionary of location identifier/substitute string pairs is assigned to its text property:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.cpubdate.text = {<span class="string">'month'</span>:<span class="string">'June'</span>, <span class="string">'day'</span>:<span class="string">'06'</span>, <span class="string">'year'</span>:<span class="string">'2006'</span>}<br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate id=&quot;cpubdate&quot;&gt;</span><span class="highlight">June 06, 2006</span><span class="stdout">&lt;/pubDate&gt;<br />  &lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;%(month)s %(day)s, %(year)s&lt;/lastBuildDate&gt;<br />  &lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot; /&gt;<br />   &lt;link id=&quot;link&quot; /&gt;<br />   &lt;guid id=&quot;guid&quot; isPermaLink=&quot;true&quot; /&gt;<br />   &lt;description id=&quot;description&quot; /&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot; /&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock"><em>lastbuilddate's</em> embedded string template follows a pattern used by Python's <a href="http://docs.python.org/lib/typesseq-strings.html">built-in string formatting</a> where <strong>%(<em>name</em>)s</strong> identifies locations
+  (e.g. <span class="highlight">%(month)s</span>) where strings can be substituted into a template to make a new string:</div>
+<div class="codeblock"><pre class="stdout">&lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;<span class="highlight">%(month)s %(day)s, %(year)s</span>&lt;/lastBuildDate&gt;</pre></div>
+<div class="textblock">String templates following this pattern are used exactly like string templates that follow the <em>string.Template</em> pattern:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.lastbuilddate.text = {<span class="string">'month'</span>:<span class="string">'June'</span>, <span class="string">'day'</span>:<span class="string">'06'</span>, <span class="string">'year'</span>:<span class="string">'2006'</span>}<br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate id=&quot;cpubdate&quot;&gt;June 06, 2006&lt;/pubDate&gt;<br />  &lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;</span><span class="highlight">June 06, 2006</span><span class="stdout">&lt;/lastBuildDate&gt;<br />  &lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot; /&gt;<br />   &lt;link id=&quot;link&quot; /&gt;<br />   &lt;guid id=&quot;guid&quot; isPermaLink=&quot;true&quot; /&gt;<br />   &lt;description id=&quot;description&quot; /&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot; /&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">String templates embedded in an XML document are automatically assigned
+  to a field's <em>template</em> property:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.cpubdate.template<br /><span class="stdout">&lt;string.Template object at 0x00F81F70&gt;</span><br />&gt;&gt;&gt; example.lastbuilddate.template<br /><span class="stdout">%(month)s %(day)s, %(year)s</span></pre></div>
+<div class="textblock">The second way to assign a string template to a field
+  is to manually assign it to a field's <em>template</em> property:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.item.link.template = <span class="string">'http://www.example.org/rss/$id'</span><br />&gt;&gt;&gt; example.item.link.template<br /><span class="stdout">&lt;string.Template object at 0x00DB7E70&gt;</span><br />&gt;&gt;&gt; example.item.link.text = {<span class="string">'id'</span>:<span class="string">'5423093'</span>}<br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate id=&quot;cpubdate&quot;&gt;June 06, 2006&lt;/pubDate&gt;<br />  &lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;June 06, 2006&lt;/lastBuildDate&gt;<br />  &lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot; /&gt;<br />   &lt;link id=&quot;link&quot;&gt;</span><span class="highlight">http://www.example.org/rss/5423093</span><span class="stdout">&lt;/link&gt;<br />   &lt;guid id=&quot;guid&quot; isPermaLink=&quot;true&quot; /&gt;<br />   &lt;description id=&quot;description&quot;&gt;Example of assigning text to a field.&lt;/description&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot; /&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">String templates can be assigned to multiple fields in one operation  by using a root or group's <em>templates</em> method:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.item.templates({<span class="string">'title'</span>:{<span class="string">'text'</span>:<span class="string">'Example Title: $content'</span>},
+... <span class="string">'ipubdate'</span>:{<span class="string">'text'</span>:<span class="string">'$month $day, $year'</span>}})<br />&gt;&gt;&gt; example.item.title.template<br /><span class="stdout">&lt;string.Template object at 0x00EA75B0&gt;</span><br />&gt;&gt;&gt; example.item.ipubdate.template<br /><span class="stdout">&lt;string.Template object at 0x00EA7690&gt;</span><br />&gt;&gt;&gt; example.item.title.text = {<span class="string">'content'</span>:<span class="string">'First Example'</span>}<br />&gt;&gt;&gt; example.item.ipubdate.text = {<span class="string">'month'</span>:<span class="string">'June'</span>, <span class="string">'day'</span>:<span class="string">'6'</span>, <span class="string">'year'</span>:<span class="string">'2006'</span>}<br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate id=&quot;cpubdate&quot;&gt;June 06, 2006&lt;/pubDate&gt;<br />  &lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;June 06, 2006&lt;/lastBuildDate&gt;<br />  &lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot;&gt;</span><span class="highlight">Example Title: First Example</span><span class="stdout">&lt;/title&gt;<br />   &lt;link id=&quot;link&quot;&gt;http://www.example.org/rss/5423093&lt;/link&gt;<br />   &lt;guid id=&quot;guid&quot; isPermaLink=&quot;true&quot; /&gt;<br />   &lt;description id=&quot;description&quot;&gt;Example of assigning text to a field.&lt;/description&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot;&gt;</span><span class="highlight">June 6, 2006</span><span class="stdout">&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textheader"><a id="attr">ATTRIBUTES</a></div>
+<div class="textblock">The value of an XML attribute can be set by assigning a string to its object attribute:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.item.guid.isPermaLink = <span class="string">'false'</span><br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate id=&quot;cpubdate&quot;&gt;June 06, 2006&lt;/pubDate&gt;<br />  &lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;June 06, 2006&lt;/lastBuildDate&gt;<br />  &lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot;&gt;Example Title: First Example&lt;/title&gt;<br />   &lt;link id=&quot;link&quot;&gt;http://www.example.org/rss/5423093&lt;/link&gt;<br />   &lt;guid id=&quot;guid&quot; isPermaLink=</span><span class="highlight">&quot;false&quot;</span><span class="stdout"> /&gt;<br />   &lt;description id=&quot;description&quot;&gt;Example of assigning text to a field.&lt;/description&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot;&gt;June 6, 2006&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">One or more existing  attribute values can be changed or one or more new  attributes  added using a field's <em>update</em> method:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.item.guid.update({<span class="string">'isPermaLink'</span>:<span class="string">'true'</span>, <span class="string">'id'</span>:<span class="string">'GUID'</span>,
+... <span class="string">'{http://www.w3.org/1999/02/22-rdf-syntax-ns#}resource'</span>:<span class="string">'http://www.example.org/rss/5423093'</span>})<br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate id=&quot;cpubdate&quot;&gt;June 06, 2006&lt;/pubDate&gt;<br />  &lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;June 06, 2006&lt;/lastBuildDate&gt;<br />  &lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot;&gt;Example Title: First Example&lt;/title&gt;<br />   &lt;link id=&quot;link&quot;&gt;http://www.example.org/rss/5423093&lt;/link&gt;<br />   &lt;guid </span><span class="highlight">id=&quot;GUID&quot;</span><span class="stdout"> </span><span class="highlight">isPermaLink=&quot;true&quot; rdf:resource=&quot;http://www.example.org/rss/5423093&quot;</span><span class="stdout"> xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot; /&gt;<br />   &lt;description id=&quot;description&quot;&gt;Example of assigning text to a field.&lt;/description&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot;&gt;June 6, 2006&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">One or more string templates for formatting attribute values can be set by assigning a dictionary of attribute name/attribute template pairs to a field's <em>atemplates</em> property:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.item.guid.atemplates = {
+... '<span class="string">{http://www.w3.org/1999/02/22-rdf-syntax-ns#}resource'</span>:<span class="string">'http://www.example.org/rss/$guid'</span>}</pre></div>
+<div class="textblock">The attribute value is then  formatted by the attribute's template  when a dictionary
+  of attribute name/dictionary pairs is passed to the attribute either with the <em>update</em> method:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.item.guid.update({
+... <span class="string">'{http://www.w3.org/1999/02/22-rdf-syntax-ns#}resource'</span>:{<span class="string">'guid':'5423094'</span>}})</pre></div>
+<div class="textblock">or by assigning a dictionary of attribute name/dictionary pairs directly to its  object attribute:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.item.guid.resource = {<span class="string">'guid'</span>:<span class="string">'5423093'</span>}<br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate id=&quot;cpubdate&quot;&gt;June 06, 2006&lt;/pubDate&gt;<br />  &lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;June 06, 2006&lt;/lastBuildDate&gt;<br />  &lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot;&gt;Example Title: First Example&lt;/title&gt;<br />   &lt;link id=&quot;link&quot;&gt;http://www.example.org/rss/5423093&lt;/link&gt;<br />   &lt;guid id=&quot;GUID&quot; isPermaLink=&quot;true&quot; </span><span class="highlight">rdf:resource=&quot;http://www.example.org/rss/5423093&quot;</span><span class="stdout"> xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot; /&gt;<br />   &lt;description id=&quot;description&quot;&gt;Example of assigning text to a field.&lt;/description&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot;&gt;June 6, 2006&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">One or more attributes can be removed by using a field's <em>purge</em> method:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.item.guid.purge(<span class="string">'{http://www.w3.org/1999/02/22-rdf-syntax-ns#}resource'</span>)<br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate id=&quot;cpubdate&quot;&gt;June 06, 2006&lt;/pubDate&gt;<br />  &lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;June 06, 2006&lt;/lastBuildDate&gt;<br />  &lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot;&gt;Example Title: First Example&lt;/title&gt;<br />   &lt;link id=&quot;link&quot;&gt;http://www.example.org/rss/5423093&lt;/link&gt;<br />   &lt;guid id=&quot;GUID&quot; isPermaLink=&quot;true&quot; /&gt;<br />   &lt;description id=&quot;description&quot;&gt;Example of assigning text to a field.&lt;/description&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot;&gt;June 6, 2006&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">An attribute can also be removed by deleting its object attribute:</div>
+<div class="codeblock">
+<pre>&gt;&gt;&gt; example.item.guid.update(
+... {<span class="string">'{http://www.w3.org/1999/02/22-rdf-syntax-ns#}resource'</span>:<span class="string">'http://www.example.org/rss/5423093'</span>})<br />&gt;&gt;&gt; <span class="keyword">del</span> example.item.guid.resource<br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate id=&quot;cpubdate&quot;&gt;June 06, 2006&lt;/pubDate&gt;<br />  &lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;June 06, 2006&lt;/lastBuildDate&gt;<br />  &lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot;&gt;Example Title: First Example&lt;/title&gt;<br />   &lt;link id=&quot;link&quot;&gt;http://www.example.org/rss/5423093&lt;/link&gt;<br />   &lt;guid id=&quot;guid&quot; isPermaLink=&quot;false&quot; /&gt;<br />   &lt;description id=&quot;description&quot;&gt;Example of assigning text to a field.&lt;/description&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot;&gt;June 6, 2006&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textheader"><a id="batch">BATCH SUBSTITUTION</a></div>
+<div class="textblock">The modulo operator can be used to assign templates and substitute text into  elements and attributes in one batch substitution.
+  Using the modulo operator without the assignment operator (<strong>%</strong>) creates a new object. Using the modulo operator with the assignment operator (<strong>%=</strong>) modifies the left-hand object. <br />
+<br />In a batch substitution, text substitutions are given the keyword <span class="string">'text'</span> and passed in a dictionary to a field:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.reset()<br />&gt;&gt;&gt; example.cpubdate %= {<span class="string">'text'</span>:{<span class="string">'month'</span>:<span class="string">'June'</span>, <span class="string">'day'</span>:<span class="string">'06'</span>, <span class="string">'year'</span>:<span class="string">'2006'</span>}}<br />&gt;&gt;&gt; example.lastbuilddate %= {<span class="string">'text'</span>:{<span class="string">'month'</span>:<span class="string">'June'</span>, <span class="string">'day'</span>:<span class="string">'06'</span>, <span class="string">'year'</span>:<span class="string">'2006'</span>}}</pre></div>
+<div class="textblock">Template assignments are identified by the keyword <span class="string">'templates'</span> and text substitutions are identified by the keyword
+  <span class="string">'subs'</span>:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.item %= {<br />... <span class="string">'templates'</span>:{<br />...     <span class="string">'title'</span>:{<span class="string">'text'</span>:<span class="string">'Example Title: $content'</span>},<br />...     <span class="string">'ipubdate'</span>:{<span class="string">'text'</span>:<span class="string">'$month $day, $year'</span>},<br />...     <span class="string">'link'</span>:{<span class="string">'text'</span>:<span class="string">'http://www.example.org/rss/$id'</span>}},<br />... <span class="string">'subs'</span>:((<br />...     {<span class="string">'text'</span>:{<span class="string">'content'</span>:<span class="string">'First Example'</span>}},<br />...     {<span class="string">'text'</span>:{<span class="string">'id'</span>:<span class="string">'5423093'</span>}}, {<span class="string">'attrib'</span>:{<span class="string">'id'</span>:<span class="string">'GUID'</span>}},<br />...     {<span class="string">'text'</span>:<span class="string">'http://www.example.org/rss/5423093'</span>},<br />...     <span class="string">'Example of assigning text to a field.'</span>,<br />...     {<span class="string">'text'</span>:{<span class="string">'month'</span>:<span class="string">'June'</span>, <span class="string">'day'</span>:<span class="string">'6'</span>, <span class="string">'year'</span>:<span class="string">'2006'</span>}}),)}<br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate id=&quot;cpubdate&quot;&gt;June 06, 2006&lt;/pubDate&gt;<br />  &lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;June 06, 2006&lt;/lastBuildDate&gt;<br />  &lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot;&gt;</span><span class="highlight">Example Title: First Example</span><span class="stdout">&lt;/title&gt;<br />   &lt;link id=&quot;link&quot;&gt;</span><span class="highlight">http://www.example.org/rss/5423093</span><span class="stdout">&lt;/link&gt;<br />   &lt;guid id=&quot;GUID&quot; isPermaLink=&quot;true&quot;&gt;</span><span class="highlight">http://www.example.org/rss/5423093</span><span class="stdout">&lt;/guid&gt;<br />   &lt;description id=&quot;description&quot;&gt;</span><span class="highlight">Example of assigning text to a field.</span><span class="stdout">&lt;/description&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot;&gt;</span><span class="highlight">June 6, 2006</span><span class="stdout">&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">Templates are stored in a dictionary under the name of the field they are assigned to (e.g. <span class="string">'title'</span>). This
+  dictionary can contain any number of templates up to but not exceeding the number of fields in the root or group to which it is passed. Text templates are string templates that are stored under the keyword <span class="string">'text'</span>.
+  Attribute templates, stored under the keyword <span class="string">'attrib'</span>, are a dictionary of pairs consisting of an attribute name and a string template . <br />
+  <br />
+  Substitutions are stored in a tuple. The number of items in a substitution's tuple must be equal to the number of fields in the root or group to which it is passed. Each
+  item in  a substitution's tuple can be a string or a dictionary of substitutions. Within a dictionary of substitutions, the keyword <span class="string">'text'</span>
+  identifies text substitutions, the value of which can be either a string or a dictionary of text template substitutions, and the keyword <span class="string">'attrib'</span> identifies attribute substitutions, the value of which is a dictionary
+  containing pairs of attribute names and  strings or  dictionaries of attribute template substitutions. All tuples containing substitutions are put in another tuple and stored under the <span class="string">'subs'</span>
+  keyword.<br />
+  <br />
+  The modulo operator can also substitute a dictionary containing pairs of field names and substitutions into every field or group in a root object in one operation:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example %= {<br />... <span class="string">'cpubdate'</span>:{<span class="string">'text'</span>:{<span class="string">'month'</span>:<span class="string">'June'</span>, <span class="string">'day'</span>:<span class="string">'06'</span>, <span class="string">'year'</span>:<span class="string">'2006'</span>}}, <br />... <span class="string">'lastbuilddate'</span>:{<span class="string">'text'</span>:{<span class="string">'month'</span>:<span class="string">'June'</span>, <span class="string">'day'</span>:<span class="string">'06'</span>, <span class="string">'year'</span>:<span class="string">'2006'</span>}},<br />... <span class="string">'item'</span>:{<span class="string">'templates'</span>:{<span class="string">'title'</span>:{<span class="string">'text'</span>:<span class="string">'Example Title: $content'</span>},
+... 	<span class="string">'ipubdate'</span>:{<span class="string">'text'</span>:<span class="string">'$month $day, $year'</span>},<br />... 	<span class="string">'link'</span>:{<span class="string">'text'</span>:<span class="string">'http://www.example.org/rss/$id'</span>}},<br />... 	<span class="string">'title'</span>:{<span class="string">'text'</span>:{<span class="string">'content'</span>:<span class="string">'First Example'</span>}},<br />... 	<span class="string">'link'</span>:{<span class="string">'text'</span>:{<span class="string">'id'</span>:<span class="string">'5423093'</span>}},<br />... 	<span class="string">'guid'</span>:{<span class="string">'attrib'</span>:{<span class="string">'id'</span>:<span class="string">'GUID'</span>}, <span class="string">'text'</span>:<span class="string">'http://www.example.org/rss/5423093'</span>},<br />... 	<span class="string">'description'</span>:{<span class="string">'text'</span>:<span class="string">'Example of assigning text to a field.'</span>},<br />... 	<span class="string">'ipubdate'</span>:{<span class="string">'text'</span>:{<span class="string">'month'</span>:<span class="string">'June'</span>, <span class="string">'day'</span>:<span class="string">'6'</span>, <span class="string">'year'</span>:<span class="string">'2006'</span>}}}}<br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate id=&quot;cpubdate&quot;&gt;</span><span class="highlight">June 06, 2006</span><span class="stdout">&lt;/pubDate&gt;<br />  &lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;</span><span class="highlight">June 06, 2006</span><span class="stdout">&lt;/lastBuildDate&gt;<br />  &lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot;&gt;</span><span class="highlight">Example Title: First Example</span><span class="stdout">&lt;/title&gt;<br />   &lt;link id=&quot;link&quot;&gt;</span><span class="highlight">http://www.example.org/rss/5423093</span><span class="stdout">&lt;/link&gt;<br />   &lt;guid id=</span><span class="highlight">&quot;GUID&quot;</span><span class="stdout"> isPermaLink=&quot;true&quot;&gt;</span><span class="highlight">http://www.example.org/rss/5423093</span><span class="stdout">&lt;/guid&gt;<br />   &lt;description id=&quot;description&quot;&gt;</span><span class="highlight">Example of assigning text to a field.</span><span class="stdout">&lt;/description&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot;&gt;</span><span class="highlight">June 06, 2006</span><span class="stdout">&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textheader"><a id="state">STATE</a></div>
+<div class="textblock">Each root, field, or group has a <em>current</em> and a <em>default</em> property. The <em>current</em> property returns the object's current state:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.current<br /><span class="stdout">&lt;Template &quot;root&quot; at dcd290&gt;</span><br />&gt;&gt;&gt; <span class="keyword">print</span> example.current<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate id=&quot;cpubdate&quot;&gt;June 06, 2006&lt;/pubDate&gt;<br />  &lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;June 06, 2006&lt;/lastBuildDate&gt;<br />  &lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot;&gt;Example Title: First Example&lt;/title&gt;<br />   &lt;link id=&quot;link&quot;&gt;http://www.example.org/rss/5423093&lt;/link&gt;<br />   &lt;guid id=&quot;GUID&quot; isPermaLink=&quot;true&quot;&gt;http://www.example.org/rss/5423093&lt;/guid&gt;<br />   &lt;description id=&quot;description&quot;&gt;Example of assigning text to a field.&lt;/description&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot;&gt;June 6, 2006&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">The <em>default</em> property returns the object's
+  default state:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.default<br /><span class="stdout">&lt;Template &quot;root&quot; at f62d10&gt;</span><br />&gt;&gt;&gt; <span class="keyword">print</span> example.default<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate id=&quot;cpubdate&quot;&gt;$month $day, $year&lt;/pubDate&gt;<br />  &lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;%(month)s %(day)s, %(year)s&lt;/lastBuildDate&gt;<br />  &lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot; /&gt;<br />   &lt;link id=&quot;link&quot; /&gt;<br />   &lt;guid id=&quot;guid&quot; isPermaLink=&quot;true&quot; /&gt;<br />   &lt;description id=&quot;description&quot; /&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot; /&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textheader"><a id="add">CONCATENATION</a></div>
+<div class="textblock">Roots, fields, and groups can be concatenated together using the addition operator.<br /><br />Roots:</div>
+<div class="codeblock">
+<pre>&gt;&gt;&gt; example.reset()<br />&gt;&gt;&gt; <span class="keyword">print</span> example + example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate id=&quot;cpubdate&quot;&gt;$month $day, $year&lt;/pubDate&gt;<br />  &lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;%(month)s %(day)s, %(year)s&lt;/lastBuildDate&gt;<br />  &lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot; /&gt;<br />   &lt;link id=&quot;link&quot; /&gt;<br />   &lt;guid id=&quot;guid&quot; isPermaLink=&quot;true&quot; /&gt;<br />   &lt;description id=&quot;description&quot; /&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot; /&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;<br /> </span><span class="highlight">&lt;rss version=&quot;2.0&quot;&gt;
+ &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate id=&quot;cpubdate&quot;&gt;$month $day, $year&lt;/pubDate&gt;<br />  &lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;%(month)s %(day)s, %(year)s&lt;/lastBuildDate&gt;<br />  &lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot; /&gt;<br />   &lt;link id=&quot;link&quot; /&gt;<br />   &lt;guid id=&quot;guid&quot; isPermaLink=&quot;true&quot; /&gt;<br />   &lt;description id=&quot;description&quot; /&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot; /&gt;<br />  &lt;/item&gt;<br /> &lt;/channel&gt;
+ &lt;/rss&gt;</span><span class="stdout">&lt;/rss&gt;</span></pre></div>
+<div class="textblock">Groups:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; <span class="keyword">print</span> example.item + example.item<br /><span class="stdout">&lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot; /&gt;<br />   &lt;link id=&quot;link&quot; /&gt;<br />   &lt;guid id=&quot;guid&quot; isPermaLink=&quot;true&quot; /&gt;<br />   &lt;description id=&quot;description&quot; /&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot; /&gt;<br />  &lt;/item&gt;<br /> </span><span class="highlight">&lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot; /&gt;<br />   &lt;link id=&quot;link&quot; /&gt;<br />   &lt;guid id=&quot;guid&quot; isPermaLink=&quot;true&quot; /&gt;<br />   &lt;description id=&quot;description&quot; /&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot; /&gt;<br />  &lt;/item&gt;</span></pre></div>
+<div class="textblock">Fields:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; <span class="keyword">print</span> example.item.title + example.item.title<br /><span class="stdout">&lt;title id=&quot;title&quot; /&gt;<br /> </span><span class="highlight">&lt;title id=&quot;title&quot; /&gt;</span></pre></div>
+<div class="textblock">Using the addition operator (<strong>+</strong>) without the assignment operator (<strong>=</strong>) results in a new object. Using
+  the addition and assignment operators together (<strong>+=</strong>) modifies the left-hand object:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.item += example.item<br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate id=&quot;cpubdate&quot;&gt;$month $day, $year&lt;/pubDate&gt;<br />  &lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;%(month)s %(day)s, %(year)s&lt;/lastBuildDate&gt;<br />  &lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot; /&gt;<br />   &lt;link id=&quot;link&quot; /&gt;<br />   &lt;guid id=&quot;guid&quot; isPermaLink=&quot;true&quot; /&gt;<br />   &lt;description id=&quot;description&quot; /&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot; /&gt;<br />  &lt;/item&gt;<br /> </span><span class="highlight">&lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot; /&gt;<br />   &lt;link id=&quot;link&quot; /&gt;<br />   &lt;guid id=&quot;guid&quot; isPermaLink=&quot;true&quot; /&gt;<br />   &lt;description id=&quot;description&quot; /&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot; /&gt;<br />  &lt;/item&gt;</span><span class="stdout"><br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textheader"><a id="mul">REPETITION</a></div>
+<div class="textblock">A root, group, or field can be repeated once by calling its <em>repeat</em> method:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.reset()<br />&gt;&gt;&gt; example.item.repeat()<br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate id=&quot;cpubdate&quot;&gt;$month $day, $year&lt;/pubDate&gt;<br />  &lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;%(month)s %(day)s, %(year)s&lt;/lastBuildDate&gt;<br />  &lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot; /&gt;<br />   &lt;link id=&quot;link&quot; /&gt;<br />   &lt;guid id=&quot;guid&quot; isPermaLink=&quot;true&quot; /&gt;<br />   &lt;description id=&quot;description&quot; /&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot; /&gt;<br />  &lt;/item&gt;
+</span><span class="highlight">&lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot; /&gt;<br />   &lt;link id=&quot;link&quot; /&gt;<br />   &lt;guid id=&quot;guid&quot; isPermaLink=&quot;true&quot; /&gt;<br />   &lt;description id=&quot;description&quot; /&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot; /&gt;<br />  &lt;/item&gt;</span><span class="stdout"><br /> &lt;/channel&gt;</span><span class="highlight"><br /></span><span class="stdout"> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">A root, group, or field can be repeated more than once by using the multiplication operator, either by itself (<strong>*</strong>),
+  which returns a new object, or along with the assignment operator (<strong>*=</strong>), which modifies the left-hand object:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.reset()<br />&gt;&gt;&gt; example.item *= <span class="int">2</span><br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate id=&quot;cpubdate&quot;&gt;$month $day, $year&lt;/pubDate&gt;<br />  &lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;%(month)s %(day)s, %(year)s&lt;/lastBuildDate&gt;<br />  &lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot; /&gt;<br />   &lt;link id=&quot;link&quot; /&gt;<br />   &lt;guid id=&quot;guid&quot; isPermaLink=&quot;true&quot; /&gt;<br />   &lt;description id=&quot;description&quot; /&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot; /&gt;<br />  &lt;/item&gt;<br /> </span><span class="highlight">&lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot; /&gt;<br />   &lt;link id=&quot;link&quot; /&gt;<br />   &lt;guid id=&quot;guid&quot; isPermaLink=&quot;true&quot; /&gt;<br />   &lt;description id=&quot;description&quot; /&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot; /&gt;<br />  &lt;/item&gt;</span><span class="stdout"><br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">A root, field, or group can be repeated and have text substituted into it by passing a string, tuple, or dictionary to its <em>repeat</em>
+  method:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.reset()<br />&gt;&gt;&gt; example.item %= (
+... <span class="string">'Example Title: First Example'</span>,
+... <span class="string">'http://www.example.org/rss/5423092'</span>,
+... <span class="string">'http://www.example.org/rss/5423092'</span>,
+... <span class="string">'Example of assigning text to a field.'</span>,
+... <span class="string">'June 06, 2006'</span>)<br />&gt;&gt;&gt; example.item.repeat((
+... <span class="string">'Example Title: Second Example'</span>,
+... <span class="string">'http://www.example.org/rss/5423093'</span>,
+... <span class="string">'http://www.example.org/rss/5423093'</span>,
+... <span class="string">'Example of group repetition.'</span>,
+... <span class="string">'June 06, 2006'</span>))<br />&gt;&gt;&gt; <span class="keyword">print</span> example<br /><span class="stdout">&lt;rss version=&quot;2.0&quot;&gt;<br /> &lt;channel&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  &lt;link&gt;http://www.example.org/&lt;/link&gt;<br />  &lt;description&gt;RSS Example&lt;/description&gt;<br />  &lt;language&gt;en-us&lt;/language&gt;<br />  &lt;pubDate id=&quot;cpubdate&quot;&gt;$month $day, $year&lt;/pubDate&gt;<br />  &lt;lastBuildDate id=&quot;lastbuilddate&quot;&gt;%(month)s %(day)s, %(year)s&lt;/lastBuildDate&gt;<br />  &lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot;&gt;</span><span class="highlight">Example Title: First Example</span><span class="stdout">&lt;/title&gt;<br />   &lt;link id=&quot;link&quot;&gt;</span><span class="highlight">http://www.example.org/rss/5423092</span><span class="stdout">&lt;/link&gt;<br />   &lt;guid id=&quot;guid&quot; isPermaLink=&quot;true&quot;&gt;</span><span class="highlight">http://www.example.org/rss/5423092</span><span class="stdout">&lt;/guid&gt;<br />   &lt;description id=&quot;description&quot;&gt;</span><span class="highlight">Example of assigning text to a field.</span><span class="stdout">&lt;/description&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot;&gt;</span><span class="highlight">June 06, 2006</span><span class="stdout">&lt;/pubDate&gt;<br />  &lt;/item&gt;<br /> </span><span class="highlight">&lt;item class=&quot;item&quot;&gt;<br />   &lt;title id=&quot;title&quot;&gt;Example Title: Second Example&lt;/title&gt;<br />   &lt;link id=&quot;link&quot;&gt;http://www.example.org/rss/5423093&lt;/link&gt;<br />   &lt;guid id=&quot;guid&quot; isPermaLink=&quot;true&quot;&gt;http://www.example.org/rss/5423093&lt;/guid&gt;<br />   &lt;description id=&quot;description&quot;&gt;Example of group repetition.&lt;/description&gt;<br />   &lt;pubDate id=&quot;ipubdate&quot;&gt;June 06, 2006&lt;/pubDate&gt;<br />  &lt;/item&gt;</span><span class="stdout"><br /> &lt;/channel&gt;<br /> &lt;/rss&gt;</span></pre></div>
+<div class="textblock">A root, field, or group can be expanded to fit a sequence of substitutions by using the power operator (<strong>**</strong>) either alone,
+  which returns a new object, or joined with the assignment operator (<strong>**=</strong>), which modifies the left-hand object:</div>
+<div class="codeblock"><pre>&gt;&gt;&gt; example.reset()<br />&gt;&gt;&gt; example.item **= ((
+... <span class="string">'Example Title: First Example'</span>,
+... <span class="string">'http://www.example.org/rss/5423092'</span>,
+... <span class="string">'http://www.example.org/rss/5423092'</span>,