[lxml-dev] Request for comments: Removing lxml.etree's default support for namespace class support
Hi all, I know, breaking compatibility is a serious topic, so I'm putting this here for an open discussion. This change would only impact code that uses the namespace class lookup to supply custom element classes to lxml.etree. Other code would continue to work. Currently, lxml.etree does namespace lookup for custom element classes by default. This has been the case in the 0.9 and 1.0 series. Starting with lxml 1.1, etree will support not only custom classes, but also custom lookup schemes for these classes. It includes a generic fallback mechanism from one lookup scheme to another if the first one fails. This means that the default support for namespace class lookup is becoming redundant, as it is also supported by a public class that provides the namespace lookup scheme. Also, the current scheme does not support a fallback other than the default element class, so code that wants to use the namespace lookup with a different fallback is still required to re-register both. To remove this redundancy, to speed up the default setup if namespace classes are /not/ used and (above all) to make the lookup API more accessible, I would like to remove the default for namespace lookup and replace it by the simplest possible mechanism that always returns the normal element classes. If namespace lookup support is needed, something like the following code would be required at setup time: from lxml import etree try: lookup = etree.ElementNamespaceClassLookup() except AttributeError: # lxml >= 0.9 and < 1.1 supports this by default pass else: # lxml >= 1.1 requires an explicit setup etree.setElementClassLookup(lookup) This code block is backwards compatible with lxml 0.9 and lxml 1.0, so new code that requires namespace class lookup could continue to support lxml from version 0.9 on, while older code that uses namespace classes would have to be updated with the above code block to support lxml 1.1 and later. Doing this switch *now* makes the above code pretty short, later changes would require version checking and the like. One of the main reasons for this change is that I would like to make the lookup mechanism explict and visible. It is a global property that impacts the entire library. Users who do not need to install their own custom classes should not be bothered with it, i.e. should be able to ignore the lookup API, the Namespace class registry, etc. For those who need a different mechanism, I believe that the current default does not make it visible enough that (for example) the functionality of the "Namespace" class registry is disabled if you select a different class lookup mechanism. So the new custom class support would work like this: * if no custom classes are used, no configuration is needed * any support for custom classes requires setting up a lookup scheme * changing the default class is done by creating and setting a default lookup scheme based on the new default classes * using the namespace lookup requires setting the ns lookup scheme, which then enables lookups based on the global Namespace registry * setting a per-parser lookup scheme enables delegation to the specific lookup registered with a parser, which in turn can deploy any of the available schemes and defaults to using the normal classes I'm also considering to replicate the Namespace registry locally in the ElementNamespaceClassLookup class. This would allow things like a per-parser namespace registry and the like. I think removing the default would also help in getting this cleaner. I'm really interested in hearing opinions on this. I think the above compatibility code makes the switch trivial to do, but I would like to hear if there are other impacts of this change that I might not have thought of. Stefan
Hi all, since there were no reactions so far, so I'll just extend my request a little. Stefan Behnel wrote:
To remove this redundancy, to speed up the default setup if namespace classes are /not/ used and (above all) to make the lookup API more accessible, I would like to remove the default for namespace lookup and replace it by the simplest possible mechanism that always returns the normal element classes. [...] One of the main reasons for this change is that I would like to make the lookup mechanism explict and visible. It is a global property that impacts the entire library. Users who do not need to install their own custom classes should not be bothered with it, i.e. should be able to ignore the lookup API, the Namespace class registry, etc. For those who need a different mechanism, I believe that the current default does not make it visible enough that (for example) the functionality of the "Namespace" class registry is disabled if you select a different class lookup mechanism.
I thought about this some more and found that having a per-parser setup as default would be pretty convenient and is an extremely small overhead compared to the default class lookup. And what's even better, making the parser lookup the default would remove the need to actually change the global lookup scheme, which avoids problems with different modules using lxml (as is already the case with objectify). So, the second proposal for custom class lookup: * if no custom classes are used, no configuration is needed * any support for custom classes should be registered at the parser level then, as before:
* changing the default class is done by creating and setting a default lookup scheme based on the new default classes * using the namespace lookup requires setting the ns lookup scheme, which then enables lookups based on the global Namespace registry [leaving out the original per-parser bit]
I think this really helps in getting custom class support in lxml cleaner. It would then be helpful to also extend the behaviour of the XML() and HTML() factories to use the default parser *iff* it matches their requirements (i.e. it *is* an XMLParser or HTMLParser respectively) and only if not, fall back to the current behaviour of using their own parser. This allows registering a lookup scheme for the default parser without loosing these functions. I'll just go and implement this on the trunk for now, so if there are any comments or diverging interests, please speak up on the list. Stefan
Hi, inheriting from the NumberElement base class there is a defined mechanism to set a text-to-pyval parser function using the _setValueParser method. Would it make sense to extend this well-defined mechanism to the general DataElement class? E.g. writing a custom datetime class looks s.th. like this: from lxml import objectify from datetime import datetime from dateutil.parser import parse from dateutil import tz # Unix epoch as datetime object EPOCH = datetime(1970, 1, 1, 0, 0, 0, 0, tzinfo=tz.tzutc()) # FIXME: Should probably be tzlocal, but this crashes under python2.4: # FIXME: ValueError: timestamp out of range for platform time_t when # FIXME: trying to calculate with datetime values # FIXME: This is due to changes in the time module, python2.3 just ignores it #_DEFAULT_TZ=tz.tzlocal() # better?? # Problem is that this rule is true now but has undergone some changes; # e.g. dst wasn't even invented until 1975 in Germany _DEFAULT_TZ=tz.tzstr('MET-1MEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00') class _parsePrecedence: yearfirst = True dayfirst = False def _findtz(name, offset): """Determine the timezone information as best as we can. Offset takes precedence over name. If neither offset nor tz name are given, fallback to use system local tz. """ if offset: return tz.tzoffset(name, offset) if name: if name == 'UTC': return tz.tzutc() else: found_tz = tz.gettz(name) if found_tz: return found_tz else: return tz.tzstr(name) return _DEFAULT_TZ class DatetimeElement(objectify.ObjectifiedDataElement): def __get(self): return _datetimeValueOf(self) pyval = property(__get) def _type(text): return _checkDatetime(text) _type = staticmethod(_type) def __add__(self, other): return _datetimeValueOf(self) + _datetimeValueOf(other) def __sub__(self, other): return _datetimeValueOf(self) - _datetimeValueOf(other) def __radd__(self, other): return _datetimeValueOf(other) + _datetimeValueOf(self) def __rsub__(self, other): return _datetimeValueOf(other) - _datetimeValueOf(self) def __cmp__(self, other): return cmp(_datetimeValueOf(self), _datetimeValueOf(other)) def __str__(self): return str(self.pyval) def _datetimeValueOf(obj): if isinstance(obj, DatetimeElement): return DatetimeElement._type(obj.text) return obj def _checkDatetime(timestr): # parse raises ValueError if not successful return parse(timestr, tzinfos=_findtz, yearfirst=_parsePrecedence.yearfirst, dayfirst=_parsePrecedence.dayfirst) def register(): datetimeType = objectify.PyType('datetime', _checkDatetime, DatetimeElement) datetimeType.xmlSchemaTypes = ("datetime",) datetimeType.register() The re-implementation of property pyval might be left out here, also the _type staticmethod. Maybe the __str__ method, too if ObjectifiedDataElement changed its __str__ method to def __str__(self): return str(self.pyval) What do you think? Regards, Holger Der Inhalt dieser E-Mail ist vertraulich. Falls Sie nicht der angegebene Empfänger sind oder falls diese E-Mail irrtümlich an Sie adressiert wurde, verständigen Sie bitte den Absender sofort und löschen Sie die E-Mail sodann. Das unerlaubte Kopieren sowie die unbefugte Übermittlung sind nicht gestattet. Die Sicherheit von Übermittlungen per E-Mail kann nicht garantiert werden. Falls Sie eine Bestätigung wünschen, fordern Sie bitte den Inhalt der E-Mail als Hardcopy an. The contents of this e-mail are confidential. If you are not the named addressee or if this transmission has been addressed to you in error, please notify the sender immediately and then delete this e-mail. Any unauthorized copying and transmission is forbidden. E-Mail transmission cannot be guaranteed to be secure. If verification is required, please request a hard copy version.
Hi Holger, Holger Joukl wrote:
inheriting from the NumberElement base class there is a defined mechanism to set a text-to-pyval parser function using the _setValueParser method. Would it make sense to extend this well-defined mechanism to the general DataElement class? [implementation of a date type]
The re-implementation of property pyval might be left out here, also the _type staticmethod. Maybe the __str__ method, too if ObjectifiedDataElement changed its __str__ method to def __str__(self): return str(self.pyval)
Writing str() in that way would not work in all cases. Just look at None, __str__() must always return a string. So, when None is returned as pyval, should __str__() return "" or "None"? Depends, right? What about numbers? Does 0 mean "0" or "False"? We could introduce an intermediate "ParsableObjectifiedDataElement" or something in that line. I don't know if there's enough use for it, though. It would only have 3-4 methods or something that don't do much. It's different in NumberElement, where the entire number protocol is implemented. BTW, I'm not opposed to integrating a date element class. As it looks, your's it pretty far advanced by now, and it's even an external Python module. I won't have the time to merge it before the end of the month, but if you can get some of the FIXME's out by then (no, *not* only the comments :), we can see if we get it into 1.1 final. Stefan
The re-implementation of property pyval might be left out here, also
_type staticmethod. Maybe the __str__ method, too if ObjectifiedDataElement changed its __str__ method to def __str__(self): return str(self.pyval)
Writing str() in that way would not work in all cases. Just look at None, __str__() must always return a string. So, when None is returned as
Stefan Behnel <behnel_ml@gkec.informatik.tu-darmstadt.de> schrieb am 11.08.2006 09:57:11: the pyval,
should __str__() return "" or "None"? Depends, right? What about numbers? Does 0 mean "0" or "False"?
We could introduce an intermediate "ParsableObjectifiedDataElement" or something in that line. I don't know if there's enough use for it,
The NoneElement returns: def __str__(self): return "None" with a pyval: property pyval: def __get__(self): return None so no problem there. As for numbers, a pyval of 0 will result in "0" and a pyval of True in "True". I don't actually see a problem here :-) though. It
would only have 3-4 methods or something that don't do much. It's different in NumberElement, where the entire number protocol is implemented.
I agree that another DataElement specialization would not be that useful here.
BTW, I'm not opposed to integrating a date element class. As it looks, your's it pretty far advanced by now, and it's even an external Python module. I won't have the time to merge it before the end of the month, but if you can get some of the FIXME's out by then (no, *not* only the comments :), we can see if we get it into 1.1 final.
Yes, works like a charm. Note that it depends on external dateutil module, though. Without that parsing and timezone handling becomes a nightmare. As for the FIXME I fear that there will be no clean solution other than forcing the ObjectifiedDatetime user to register a _DEFAULT_TZ containing the explicit dst rule. Date/time handling is evil. Btw.: ObjectifiedElement .text and .pyval are read-only (which is a good thing imho). Is it possible to have a way to modify the text of the underlying cnode from within a custom ObjectifiedDataElement class, e.g. in _init()? I know this i possible when implementing this in pyrex, but for a pure-python implementation? The background is that for the ObjectifiedDatetime class I might optionally want to change the .text to ISO format. Regards, Holger Der Inhalt dieser E-Mail ist vertraulich. Falls Sie nicht der angegebene Empfänger sind oder falls diese E-Mail irrtümlich an Sie adressiert wurde, verständigen Sie bitte den Absender sofort und löschen Sie die E-Mail sodann. Das unerlaubte Kopieren sowie die unbefugte Übermittlung sind nicht gestattet. Die Sicherheit von Übermittlungen per E-Mail kann nicht garantiert werden. Falls Sie eine Bestätigung wünschen, fordern Sie bitte den Inhalt der E-Mail als Hardcopy an. The contents of this e-mail are confidential. If you are not the named addressee or if this transmission has been addressed to you in error, please notify the sender immediately and then delete this e-mail. Any unauthorized copying and transmission is forbidden. E-Mail transmission cannot be guaranteed to be secure. If verification is required, please request a hard copy version.
Holger Joukl wrote:
Stefan Behnel wrote:
def __str__(self): return str(self.pyval)
Writing str() in that way would not work in all cases. Just look at None, __str__() must always return a string. So, when None is returned as pyval, should __str__() return "" or "None"? Depends, right? What about numbers? Does 0 mean "0" or "False"?
The NoneElement returns: def __str__(self): return "None"
with a pyval: property pyval: def __get__(self): return None
I know, I've written that code not too long ago. ;) I was just trying to say that the gain is relatively low, as there are only few simple methods that can be provided and many use cases still have to reimplement some of them. So I don't see a noticeable improvement.
BTW, I'm not opposed to integrating a date element class. As it looks, your's it pretty far advanced by now, and it's even an external Python module.
Yes, works like a charm. Note that it depends on external dateutil module, though.
Which is this, I assume: http://labix.org/python-dateutil Ok, that's too bad, We can't rely on external modules for the lxml distribution, at least not for something that's not strictly required for all users.
Btw.: ObjectifiedElement .text and .pyval are read-only (which is a good thing imho). Is it possible to have a way to modify the text of the underlying cnode from within a custom ObjectifiedDataElement class, e.g. in _init()? I know this i possible when implementing this in pyrex, but for a pure-python implementation? The background is that for the ObjectifiedDatetime class I might optionally want to change the .text to ISO format.
Ah, good question. Not currently, I believe. But you're right, there might be cases where it makes sense to update the text from a subclass... Maybe adding a 'private' property '__text' might help here, or rather an explicit setter function '__updateTextInPlace(self, text)' ? Stefan
Stefan Behnel <behnel_ml@gkec.informatik.tu-darmstadt.de> schrieb am 11.08.2006 10:59:04:
I was just trying to say that the gain is relatively low, as there are only few simple methods that can be provided and many use cases still have to reimplement some of them. So I don't see a noticeable improvement.
Probably the only gain would be for a objectify newbie that he/she needn't think too much about implementing the .pyval, __str__, ._type stuff. But I will rather think of a doc patch then to just document this a little more extensively (after my holidays _:-)
BTW, I'm not opposed to integrating a date element class. As it looks, your's it pretty far advanced by now, and it's even an external Python module.
Yes, works like a charm. Note that it depends on external dateutil module, though.
Which is this, I assume:
Right.
Ok, that's too bad, We can't rely on external modules for the lxml distribution, at least not for something that's not strictly required for all users.
Btw.: ObjectifiedElement .text and .pyval are read-only (which is a good thing imho). Is it possible to have a way to modify the text of the underlying cnode from within a custom ObjectifiedDataElement class, e.g. in _init()? I know this i possible when implementing this in pyrex, but for a pure-python implementation? The background is that for the ObjectifiedDatetime class I might
Maybe we can fallback to the datetime standard mechanisms if dateutil isn't installed, but then TZ handling and parsing will be far more restricted/error-prone. Will think of that. optionally
want to change the .text to ISO format.
Ah, good question. Not currently, I believe. But you're right, there might be cases where it makes sense to update the text from a subclass...
Maybe adding a 'private' property '__text' might help here, or rather an explicit setter function '__updateTextInPlace(self, text)' ?
S.th. like this would be nice. And I still think not letting the user change the text from the outside is a good thing, at least as long as changing the .text might result in an object type <-> text value mismatch. Holger Der Inhalt dieser E-Mail ist vertraulich. Falls Sie nicht der angegebene Empfänger sind oder falls diese E-Mail irrtümlich an Sie adressiert wurde, verständigen Sie bitte den Absender sofort und löschen Sie die E-Mail sodann. Das unerlaubte Kopieren sowie die unbefugte Übermittlung sind nicht gestattet. Die Sicherheit von Übermittlungen per E-Mail kann nicht garantiert werden. Falls Sie eine Bestätigung wünschen, fordern Sie bitte den Inhalt der E-Mail als Hardcopy an. The contents of this e-mail are confidential. If you are not the named addressee or if this transmission has been addressed to you in error, please notify the sender immediately and then delete this e-mail. Any unauthorized copying and transmission is forbidden. E-Mail transmission cannot be guaranteed to be secure. If verification is required, please request a hard copy version.
Hi Stefan, somethings is going wrong here:
root = objectify.Element('root') root <Element root at 2bfcd8> root.x = 1 root.y = 2 print root root = None [ObjectifiedElement] x = 1 [IntElement] y = 2 [IntElement] root.getroottree().getroot() <Element root at 1ec9e0> print root.getroottree().getroot() root = None [ObjectifiedElement] root.getroottree() <etree._ElementTree object at 0x2bf418> print root.getroottree().getroot().getroottree() <etree._ElementTree object at 0x2bf288>
I'm not doing something wrong, am I? Holger Der Inhalt dieser E-Mail ist vertraulich. Falls Sie nicht der angegebene Empfänger sind oder falls diese E-Mail irrtümlich an Sie adressiert wurde, verständigen Sie bitte den Absender sofort und löschen Sie die E-Mail sodann. Das unerlaubte Kopieren sowie die unbefugte Übermittlung sind nicht gestattet. Die Sicherheit von Übermittlungen per E-Mail kann nicht garantiert werden. Falls Sie eine Bestätigung wünschen, fordern Sie bitte den Inhalt der E-Mail als Hardcopy an. The contents of this e-mail are confidential. If you are not the named addressee or if this transmission has been addressed to you in error, please notify the sender immediately and then delete this e-mail. Any unauthorized copying and transmission is forbidden. E-Mail transmission cannot be guaranteed to be secure. If verification is required, please request a hard copy version.
Hi Holger, Holger Joukl wrote:
somethings is going wrong here:
root = objectify.Element('root') root <Element root at 2bfcd8> root.x = 1 root.y = 2 print root root = None [ObjectifiedElement] x = 1 [IntElement] y = 2 [IntElement] root.getroottree().getroot() <Element root at 1ec9e0> print root.getroottree().getroot() root = None [ObjectifiedElement] root.getroottree() <etree._ElementTree object at 0x2bf418> print root.getroottree().getroot().getroottree() <etree._ElementTree object at 0x2bf288>
I'm not doing something wrong, am I?
Nope. Was a premature optimisation with side-effects in current SVN. I changed objectify.Element() to always reuse the same document as the main use case is to add these things to other documents anyway. Pretty bad idea. Now that you said it, there are actually a lot of problems with it. Just reverted. Stefan
Hi Stefan, is it intentional/unavoidable that the element type returned by DataElement is always ObjectifiedElement, before putting it into an father element: >>> what = objectify.DataElement(18) >>> print what value = '18' [ObjectifiedElement] * py:pytype = 'int' >>> what = objectify.DataElement("hallo") >>> print what value = 'hallo' [ObjectifiedElement] * py:pytype = 'str' >>> what = objectify.DataElement("17", _pytype="str") >>> print what value = '17' [ObjectifiedElement] * py:pytype = 'str' >>> root = objectify.Element('root') >>> root.what = what >>> print root root = None [ObjectifiedElement] what = '17' [StringElement] * py:pytype = 'str' >>> Holger Der Inhalt dieser E-Mail ist vertraulich. Falls Sie nicht der angegebene Empfänger sind oder falls diese E-Mail irrtümlich an Sie adressiert wurde, verständigen Sie bitte den Absender sofort und löschen Sie die E-Mail sodann. Das unerlaubte Kopieren sowie die unbefugte Übermittlung sind nicht gestattet. Die Sicherheit von Übermittlungen per E-Mail kann nicht garantiert werden. Falls Sie eine Bestätigung wünschen, fordern Sie bitte den Inhalt der E-Mail als Hardcopy an. The contents of this e-mail are confidential. If you are not the named addressee or if this transmission has been addressed to you in error, please notify the sender immediately and then delete this e-mail. Any unauthorized copying and transmission is forbidden. E-Mail transmission cannot be guaranteed to be secure. If verification is required, please request a hard copy version.
Hi Holger, Holger Joukl wrote:
is it intentional/unavoidable that the element type returned by DataElement is always ObjectifiedElement
That's not intentional. It's the fast path in _lookupElementClass that strikes here: if c_node.parent is NULL or not tree._isElement(c_node.parent): return ObjectifiedElement # if element has children => no data class if cetree.findChildForwards(c_node, 0) is not NULL: return ObjectifiedElement Only after that, it checks the attributes of the element that determine the element type. There are two ways to change that. * We could move the above code section behind the attribute tests * I thought about adding a C level function for creating new elements anyway. Something like that is already in etree, but it could be extended with an argument for an explicit lookup function (or element class) and made public. It's not as easy as it looks, though, as element objects are created in the elementFactory function, which would have to be adapted as well... Don't know if the second is really viable. The first is easier anyway... Stefan
Hi Holger,
Holger Joukl wrote:
is it intentional/unavoidable that the element type returned by DataElement is always ObjectifiedElement
That's not intentional. It's the fast path in _lookupElementClass that strikes here:
if c_node.parent is NULL or not tree._isElement(c_node.parent): return ObjectifiedElement
# if element has children => no data class if cetree.findChildForwards(c_node, 0) is not NULL: return ObjectifiedElement
Only after that, it checks the attributes of the element that determine
element type.
There are two ways to change that.
* We could move the above code section behind the attribute tests
* I thought about adding a C level function for creating new elements anyway. Something like that is already in etree, but it could be extended with an argument for an explicit lookup function (or element class) and made
It's not as easy as it looks, though, as element objects are created in
lxml-dev-bounces@codespeak.net schrieb am 11.08.2006 12:57:54: the public. the
elementFactory function, which would have to be adapted as well...
Don't know if the second is really viable. The first is easier anyway...
If everything else works as is plus the mentioned thing works better, why not go for the simpler solution? It isn't a real problem at the moment as the DataElements I produce get promptly inserted into a father element and then behave nicely, but... Btw. Shouldn't the default Element class in _guessElementClass() become StringElement, to make this
root = objectify.fromstring("""<root><s></s></root>""") print root root = None [ObjectifiedElement] s = None [ObjectifiedElement]
finally result into StringElements for empty leaf elements? Holger Der Inhalt dieser E-Mail ist vertraulich. Falls Sie nicht der angegebene Empfänger sind oder falls diese E-Mail irrtümlich an Sie adressiert wurde, verständigen Sie bitte den Absender sofort und löschen Sie die E-Mail sodann. Das unerlaubte Kopieren sowie die unbefugte Übermittlung sind nicht gestattet. Die Sicherheit von Übermittlungen per E-Mail kann nicht garantiert werden. Falls Sie eine Bestätigung wünschen, fordern Sie bitte den Inhalt der E-Mail als Hardcopy an. The contents of this e-mail are confidential. If you are not the named addressee or if this transmission has been addressed to you in error, please notify the sender immediately and then delete this e-mail. Any unauthorized copying and transmission is forbidden. E-Mail transmission cannot be guaranteed to be secure. If verification is required, please request a hard copy version.
Hi Holger, Holger Joukl wrote:
Holger Joukl wrote:
is it intentional/unavoidable that the element type returned by DataElement is always ObjectifiedElement
That's not intentional. It's the fast path in _lookupElementClass that strikes here:
if c_node.parent is NULL or not tree._isElement(c_node.parent): return ObjectifiedElement
# if element has children => no data class if cetree.findChildForwards(c_node, 0) is not NULL: return ObjectifiedElement
Only after that, it checks the attributes of the element that determine the element type.
* We could move the above code section behind the attribute tests
If everything else works as is plus the mentioned thing works better, why not go for the simpler solution?
Yup, did that. I also fixed a couple of problems related to different data types as I was at it. We don't currently have a way to check for the real Python types from PyType registered types, only string parsing is supported. However, the real types are passed to DataElement and must be treated similarly. It works for the standard Python types for now and also for custom types that provide a proper __str__() for conversion to XML data content.
Btw. Shouldn't the default Element class in _guessElementClass() become StringElement, to make this
root = objectify.fromstring("""<root><s></s></root>""") print root root = None [ObjectifiedElement] s = None [ObjectifiedElement]
finally result into StringElements for empty leaf elements?
It only looks wrong if you call the element "s", I guess... :) But I changed it so that if the element has * no type annotation and * no children and * no text content then, if it * has an element as parent it defaults to StringElement * has no parent it defaults to ObjectifiedElement I think that makes sense. Stefan
Stefan Behnel wrote: [snip]
So, the second proposal for custom class lookup:
* if no custom classes are used, no configuration is needed * any support for custom classes should be registered at the parser level
+1 for per-parser custom class lookup. So far no objections to the first mail either. :) Regards, Martijn
On Fri, 2006-08-11 at 06:57 +0200, Stefan Behnel wrote:
I thought about this some more and found that having a per-parser setup as default would be pretty convenient and is an extremely small overhead compared to the default class lookup.
First off, thanks for getting 1.0.3 out so quickly. Really helped with my problems, and replace has been a very handy convenience function. I was actually just getting ready to ask you for per-parser custom class support when I came across you already talking about implementing it. It's actually an essential feature for me to be able to take advantage of the custom element classes, as in my application (XML based middleware) both the middleware layer and the applications all handle XML and all exist in the same process. Right now, an application can only change the default element class if it's very careful to make sure to restore it so it doesn't screw up the middleware, and even that solution is going to be impossible once the architecture goes multi-threaded. So, yeah, I'm pretty excited about getting this feature. -- John Krukoff <jkrukoff@ltgc.com> Land Title Guarantee Company
participants (4)
-
Holger Joukl
-
John Krukoff
-
Martijn Faassen
-
Stefan Behnel