
#################################
Migration and modernization guide
#################################


=========================
Migrating to version 2.13
=========================


----------------------
Changes to ll.xist.xsc
----------------------

xsc.Namespace.tokenize no longer has an encoding argument, but operates
on a unicode string directly. You can either use the result of a
asString call or decode the result of an asBytes call yourself.


=========================
Migrating to version 2.11
=========================


----------------------
Changes to ll.xist.xsc
----------------------

The function ToNode has been renamed to tonode.

ll.xist.Context no longer subclasses list. If you need a stack for your
context, simply add the list as an attribute of the context object.


-------------------
Code rearrangements
-------------------

The iterator stuff from ll.xist.xfind has been moved to the ll package/
module, i.e. you have to use ll.first instead of ll.xist.xfind.first.


--------------------------
Changes to the walk method
--------------------------

The walk method has changed again. There are no inmodes and outmodes
any longer. Instead input and output are Cursor objects. If you're
using your own walk filters, you have to update them. For different
output modes you can use the methods walknode, walkpath or walkindex
instead of using the cursor yielded by walk.

The node methods find and findfirst have been removed. Use xsc.Frag
(node.walk(...) or node.walk(...)[0] instead.


---------------------
Changes to publishing
---------------------

Publishing has changed: If you've used the method repr before to get a
string representation of an XML tree, you have to use asrepr instead
now (repr is a generator which will produce the string in pieces).


---------------------------
Changes to the xfind module
---------------------------

The functions item, first, last, count and iterone as well as the class
Iterator have been moved to the ll module.


-------------------------
Migrating to version 2.10
-------------------------


Changes to publishing
#####################

Publishing has been changed from using a stream API to using a iterator
API. If you've been using Publisher.write or Publisher.writetext (in
your own publish methods) you must update your code by replacing
publisher.write(foo) with yield publisher.encode(foo) and
publisher.writetext(foo) with yield publisher.encodetext(foo).


Changes to the test suite
#########################

The test suite now uses py.test, so if you want to run it you'll need
py.test.


Changes to ll.xist.ns.code
##########################

The code in a ll.xist.ns.code.pyexec object is no longer executed at
construction time, but at conversion time. So if you relied on this
fact (e.g. to make a namespace available for parsing the rest of the
XML file) you will have to change your code.


Removed namespaces
##################

The namespace modules ll.xist.ns.css and ll.xist.ns.cssspecials have
been removed.


------------------------
Migrating to version 2.9
------------------------


Changes to exceptions
#####################

All exception classes have been moved from ll.xist.errors to
ll.xist.xsc.


Changes to XML name handling
############################

The class attribute xmlname no longer gets replaced with a tuple
containing both the Python and the XML name. If you want to get the
Python name, use foo.__class__.__name__.


Changes to the methods walk, find and findfirst
###############################################

The argument filtermode has been renamed to inmode and (for walk)
walkmode has been renamed to outmode.


------------------------
Migrating to version 2.8
------------------------


Changes to display hooks
########################

The way XIST uses sys.displayhook has been enhanced. To make use of
this, you might want to update your Python startup script. For more
info see the installation instructions.


Changes to the xmlns attribute
##############################

Each element (or entity, or processing instruction) class had an
attribute xmlns that references the namespace module. This attribute
has been renamed to __ns__.


Other minor changes
###################

ll.xist.ns.specials.x has been renamed to ll.xist.ns.specials.ignore.

ll.xist.xfind.item no longer handles slices. If you've used that
functionality, you may now use slices on XFind operators, and
materilize the result, i.e. replace xfind.slice(foo, 1, -1) with list
(foo[1:-1]), if foo is an XFind operator. Otherwise you can use list
(foo)[1:-1]


------------------------
Migrating to version 2.7
------------------------


Changes to ll.xist.xfind
########################

The functions xfind.first and xfind.last now use xfind.item, so they
will raise an IndexError when no default value is passed. To get the
old behaviour, simply pass None as the default.


------------------------
Migrating to version 2.6
------------------------


Changes to the publishing API
#############################

The top level publishing method in the publisher has been renamed from
dopublication to publish. If you're using the publishing API directly
(instead of the node methods asBytes and write), you'll have to update
your code.

The method that writes a unicode object to the output stream has been
renamed from publish to write. This is only relevant when you've
overwritten the publish method in your own node class (e.g. in JSP tag
library directives or similar stuff, or for special nodes that publish
some text literally).


Changes to the presentation API
###############################

The presentation API has been changed too: The top level presentation
method in the presenter has been renamed from dopresentation to
present. This is only relevant if you've written your own presenter, or
are using the presentation API directly (instead of the node method
repr).


Parsing HTML
############

Parsing HTML is now done via libxml2's HTML parser, instead of using
TidyLib of mxTidy. You can no longer pass arguments to tidy. Only the
boolean values of the tidy argument will be used. There are no other
visible changes to the API but the result of parsing might have
changed.


Removed APIs and scripts
########################

The script xscmake.py has been removed.

The visit method has been removed.

ll.xist.xsc.FindOld has been removed.

ll.xist.ns.xml.header has been renamed to ll.xist.ns.xml.declaration.


------------------------
Migrating to version 2.5
------------------------


Changes to content model
########################

The boolean class attribute empty for element classes has been replaced
by an object model. empty is still supported, but issues a
PendingDeprecationWarning. If you don't want to specify a proper
content model for your own elements you can replace empty = False with
model = True (which is a shortcut for model = sims.Any()) and empty =
True with model = False (which is a shortcut for model = sims.Empty()).


------------------------
Migrating to version 2.4
------------------------


Changes to parsing
##################

Parsing has changed internally, but the module level parsing functions
in ll.xist.parsers are still available (and will create a parser on the
fly), but a few arguments have changed:

handler
    This argument is no longer available, if you need a special
    handler, you have to subclass ll.xist.parsers.Parser and call its
    parsing methods.
parser
    This argument has been renamed to saxparser and is not a SAX2
    parser instance any longer, but a callable that will create a SAX2
    parser.
sysid
    sysid is now available for all parsing functions not just
    parseString.


Changes to converter contexts
#############################

ll.xist.converters.Converter.__getitem__ now doesn't use the key passed
in, but key.Context as the real dictionary key. This has the following
consequences:

  * If you want a unique context for your own element class, you must
    implement a new Context class (otherwise you'd get
    ll.xist.xsc.Element.Context):

        class Foo(xsc.Element):
           empty = False

           class Context(xsc.Element.Context):
              def __init_(self):
                 xsc.Element.Context.__init__(self)
                 ...


  * Subclasses that don't overwrite Context (as well as instances of
    those classes) can be passed to
    ll.xist.converters.Converter.__getitem__ and the unique base class
    context object will be returned.


Changed namespaces
##################

The character reference classes from ll.xist.ns.ihtml that are
duplicates of those in ll.xist.ns.chars have been removed, so you have
to use ll.xist.ns.chars for those characters in addition to
ll.xist.ns.ihtml


------------------------
Migrating to version 2.3
------------------------


Changes in namespace handling
#############################

Namespace handling has changed. There are no entity or processing
instruction prefixes any longer and creating a proper Prefixes object
has been simplified. For example:

    prefixes = xsc.Prefixes()
    prefixes.addElementPrefixMapping(None, html)
    prefixes.addElementPrefixMapping("svg", svg)


can be simplified to:

    prefixes = xsc.Prefixes(html, svg=svg)


The three arguments elementmode, entitymode and procinstmode for the
publishing methods have been combined into prefixmode, which is used
for elements only.


Changed namespaces
##################

The character reference classes from ll.xist.ns.html have been moved to
a separate namespace ll.xist.ns.chars.

The processing instructions eval_ and exec_ from the ll.xist.ns.code
module have been renamed to pyeval and pyexec.


Changed method names
####################

The method names beginPublication, endPublication and doPublication
have been lowercased.


------------------------
Migrating to version 2.2
------------------------


Attribute methods
#################

The Element methods for accessing attributes have been deprecated. So
instead of node.hasattr("attr"), you should use:

    "attr" in node.attrs


The same holds for checking whether an attribute is allowed. You can
use the following code:

    "attr" in node.Attrs


or:

    "attr" in NodeClass.Attrs


or:

    NodeClass.isallowed("attr")


Many Attrs methods have gained an additional parameter xml, which
specifies whether an attribute name should be treated as the XML or the
Python name of the attribute. Make sure that you're not mixing up your
arguments in the function call. The safest method for this is using
keyword arguments, e.g.:

    node.attr.get("attr", default=42)



JSP directive page element
##########################

A contentType attribute is no longer generated for the
ll.xist.ns.jsp.directive_page. You have to explicitely use an attribute
contentType="text/html" to get a contentType attribute in the resulting
JSP. The charset option is generated automatically from the encoding
specified in the publisher.


autoimg changes
###############

ll.xist.htmlspecials.autoimg will no longer touches existing width or
height attributes, so e.g. setting the width to twice the image size
via width="2*%(width)s" no longer works. You have to implement your own
version of autoimg if you need this.


find changes
############

find has been completely rewritten to use the new tree traversal
filters. For backwards compatibility a filter functor
ll.xist.xsc.FindOld exists that takes the same arguments as the old
find method. I.e. you can replace:

    node.find(
       type=html.a,
       attr={"href": None},
       searchchildren=True
    )


with:

    node.find(
       xsc.FindOld(
          type=html.a,
          attr={"href": None},
          searchchildren=True
       ),
       skiproot=True
    )


But one minor difference remains: when skiproot is set to true in the
new find method, the attributes of the root element will not be
traversed. With the old method they would be traversed.


doc changes
###########

programlisting has been renamed to prog.


Namespace changes
#################

Namespaces can no longer be instantiated. Instead you have to derive a
class from Namespace. The xmlprefix argument from the constructor
becomes a class attribute xmlname and the argument xmlname becomes
xmlurl.

Adding element classes to the namespace is now done with the Namespace
classmethod update. If you want the turn a namespace into a module, you
can use the classmethod makemod instead of update.

    xmlns = xsc.Namespace("foo", "http://www.foo.com/", vars()


    class xmlns(xsc.Namespace):
       xmlname = "foo"
       xmlurl = "http://www.foo.com/"
    xmlns.makemod(vars())



------------------------
Migrating to version 2.1
------------------------

  * The method withSep has been renamed to withsep.
  * The argument defaultEncoding for the various parsing functions has
    been renamed to encoding.


------------------------
Migrating to version 2.0
------------------------


Attribute handling
##################

The biggest change is in the way attributes are defined. In older
versions you had to define a class attribute attrHandlers that mapped
attribute names to attribute classes. This created problems with
?illegal? attribute names (e.g. class and http-equiv in HTML), so for
them an ugly workaround was implemented. With 2.0 this is no longer
neccessary. Defining attributes is done via a class Attrs nested inside
the element class like this:

    class foo(xsc.Element):
       class Attrs(xsc.Element.Attrs):
          class bar(xsc.TextAttr)
             "The bar attribute"
             default = "spam"
             values = ("spam", "eggs")
             required = True
          class baz(xsc.URLAttr):
             "The baz attribute"


Default values, set of allowed attributes values and whether the
attribute is required can be defined via class attributes as shown
above. You should (directly or indirecty) inherit from
xsc.Element.Attrs, because this class implements handling of global
attributes. If you want to inherit some attributes (e.g. from your base
class), you can derive from the appropriate Attrs class. Removing an
attribute you inherited can be done like this:

    class bar(foo):
       class Attrs(foo.Attrs):
          baz = None


This removes the attribute baz inherited from foo.

For attribute names that are no legal Python identifiers, the same
method can be used as for element classes: Define the real XML name via
a class attribute. This class attribute has been renamed from name to
xmlname.

This also means that you always have to use the Python name when using
attributes now. The XML name will only be used for parsing and
publishing.

XIST 2.0 tries to be as backwards compatible as possible: An existing
attrHandlers attribute will be converted to an Attrs class on the fly
(and will generate a DeprecationWarning when the class is created). An
Attrs class will automatically generate an attrHandlers attribute, so
it's possible to derive from new element classes in the old way. The
only situation where this won't work, is with attributes where the
Python and XML name differ, you have to use ?new style? attributes
there.


Namespace support
#################

XIST supports XML namespaces now and for parsing it's possible to
configure which namespaces should be available for instantiating
classes from. For more info about this refer to the documentation for
the class Prefixes.

Before 2.0 the XML name for a namespace object was pretty useless, now
it can be used as the namespace name in xmlns attributes and it will be
used for that when publishing and specifying an elementmode of 2 in the
call to the publishing method or the constructor of the publisher.

Namespace objects should now be named xmlns instead of namespace as
before.


Global attributes
#################

Global attributes are supported now, e.g. the attributes xml:lang and
xml:space can be specified in an element constructor like this:

    from ll.xist import xsc
    from ll.xist.ns import html, xml

    node = html.html(
       content,
       {(xml, "lang"): "en", (xml, "space"): "preserve"},
       lang="en"
    )


Instead of the module object (which must contain a namespace object
named xmlns), you can also pass the namespace object itself (i.e.
xml.xmlns) or the namespace name (i.e. "http://www.w3.org/XML/1998/
namespace").


Namespace changes
#################

The classes XML and XML10 have been moved from ll.xist.xsc to
ll.xist.ns.xml.

All the classes in ll.xist.ns.specials that are specific to HTML
generation have been moved to the new module ll.xist.ns.htmlspecials.

The module ll.xist.ns.html has been updated to the XHTML specification,
so there might be some changes. The new feature for specifying
attribute restrictions has been used, so e.g. you'll get warnings for
missing alt attributes in img elements. These warnings are issued via
the warning framework. Refer to the documentation for the warnings
module to find out how to configure the handling of these warnings.


Miscellaneous
#############

XIST now requires at least Python 2.2.1 because the integer constants
True and False are used throughout the code wherever appropriate. These
constants will become instances of the new class bool in Python 2.3.
You might want to change your code too, to use these new constant (e.g.
when setting the element class attribute empty).

Using mixed case method names was a bad idea, because this conflicts
with Python's convention of using all lowercase names (without
underscores). These method names will be fixed in the next few XIST
versions. The first names that where changed were the element methods
getAttr and hasAttr, which have been renamed to getattr and hasattr
respectively. getAttr and hasAttr are still there and can be called
without generating DeprecationWarnings, but they will start to generate
warnings in the upcoming versions.
