| « SQLComp, an experimental LINQ-in-Python | How Python wins on the Web » |
Templating languages, and YAPTL
PyMeld is the coolest templating language ever, because it's not a templating language, it's a template engine. It's what I like to call an "active" or "push" templating engine, that is, rather than the Cheetah school of passing a model object or dictionary to the template and letting the templating engine "pull" the data from it and figure it out, your controller code handles the vast majority of the logic ("pushes" the data), and the engine just makes it simple to manipulate the document. This is the best way for a templating language to be, because your templates are similar, and you're using a Real Programming Language to do what Real Programming Languages should be doing instead of these fake templating languages. In addition, your template files are nice and simple, and can be pulled right out of Dreamweaver and your graphic designer without having to mark it up with stuff.
PyMeld isn't without its issues, though. It's really slow and inefficient, as its powered by regular expressions and must reparse every time you run an operation on it. It's license requires you to pay money to use it commercially, which sort of sucks too.
There's a few reimplementations around, but they're very ZPT-like and, I believe, miss the point of PyMeld. PyMeld is just a badass, amazing, extra-special DOM library, and these reimplementations try to turn it into YAPTL. Meld4 sticks to PyMeld's roots, but throws the power of ElementTree behind it. I also added a couple of utility functions: fill() implements something similar but cooler than ASP.NET's MasterPages, and push_pull() is for those people who really can't bear to use an active templating engine, and will accept a dictionary that will fill the keys of a template and automatically handle lists, nested dicts and primitives.
8 comments
I like the idea of push_pull; it gives people used to pull templating systems a place to start.
FWIW, I consider ElementTree the badass DOM replacement API rather than anything built on top of it. I'm not real crazy about the idea of hiding the ElementTree API from people; it's very well-documented, and very simple. That's why for meld3 I chose to expose and extend the ElementTree _ElementInterface API for nodes rather than creating another entirely different one (or sticking to the PyMeld API). While this won't let you use "old" PyMeld templates, that wasn't a goal of mine (and it appears neither for meld4 as it has some slight API differences).
Certainly the intent of meld3 wasn't to just "create YAPTL", although any templating language written in Python is just that. It's also not a ZPT clone or anything. The only thing ZPT-like about meld3 is its use of the names "content", "repeat", "replace", and "structure". This was a nod to my Zopish background and for the tasks that really do need to be done when doing web templating. It has nothing else whatsoever to do with ZPT. It has the same goals as PyMeld and your meld4.
meld3, does support the full API functionality of PyMeld. The main differences:
- getattr on nodes isn't tasked with searching for
elements with meld ids (that's .findmeld() in
meld3). - You can get at __mod__ functionality via fillmelds() instead
- Instead of using __setitem__ to set an attribute value, you use either the ElementTree API (node.attrib['k'] = 'v') or the meld3 'attributes' method (node.attributes(**kw)).
There just isn't a lot to the PyMeld API, so supporting all of its features was pretty simple (ElementTree already had them all; I just took the tact of exposing them).
meld3 also lets you do some web page templating a bit more easily that are a bit harder to do in PyMeld: repeating elements using an iterator, diffing structure of meld templates.
If the audience for meld4 is templating people, I'll also note that you'll want to try to use your templates in WYSIWYG editors before you lead other people to beleieve they'll work well in those editors... a lot of WYSIWYG editors don't seem to deal well with XML/XHTML templates and break them badly in bizarre ways (NVU comes to mind). Lots of browsers also have major problems dealing with namespace output. This is why meld3 has an HTML parser and serializer, and an XHTML serializer that strips out namespace output. meld3 also attempts to explicitly allow for "pipelineing" where you can output a serialized version of a tree with the ids intact for later processing (maybe by XSL or another meld system).
There is the equivalent of your fill() in the z3meld bindings for Zope3 (see plope.com).
It would be great to try to collaborate on this stuff if we could find some common ground.
Of course, I'd love to collaborate. Maybe I missed it, but does meld3 have a way to get the parent node of a given meld? Or an equivalent to ._content?
Yes. Every meld3 node has a 'parent' attribute, and this attribute is maintained as you move nodes around via the elementtree/meld3 API. You can delete a node from its parent by calling 'node.deparent()'.
The closest equivalent to viewing the equivalent of PyMeld's ._content is to call 'node.shortrepr()'.
The equivalent to the concept of assigning to ._content is done via "node.content('some stuff')". If the content is another node as opposed to text, you need to do a multiline thing which deletes the children of the node andthe nodes. This could be made easier if meld3 allowed its "content" method to accept another node too instead of only allowing text (which is simple and is probably a good idea). The 'content' method accepts an optional second argument named 'structure' which if it's true will turn off HTML escaping of the text passed in, which allows you to do things like:
node.replace('some suff', structure=True)
Replacing a node is done via "node.replace('some stuff')". This also accepts the structure flag and could also accept a node instead of text (it doesn't now).
"You can also use the elementtree API against all nodes, and do node.text = 'foo' or node._children = [] to clear all child nodes, node.find('bar') to find the first bar node beneath this node, and so on.
Anyway, it'd be great if you could take a closer look at meld3 and see what you don't like about it; it can obviously be changed to make things easier as necessary.
Doh... the above blockquote demonstrating structure should have tags around the "some stuff" (implying that what you pass in is html).
A good comparison is to the View and Controller layers in Apple-style MVC.
In Apple MVC, the View layer consists solely of graphical widget objects, assembled live and stored in serialized form (.nib) using Interface Builder, and the Controller layer contains the glue code that pulls data from the Model layer and inserts it into the View objects.
With DOM-style templating engines, the tagged HTML file is analogous to the .nib file, the templating engine the AppKit framework that turns this data back into live objects, and the Python code that manipulates these objects the Controller layer.
Incidentally, I do think there's something to be said for stuff like automatic interpolation of dictionary values or instance variables to reduce the amount of tedious glue code developers need to write in common situations (c.f. Cocoa Bindings). Though I'd suggest you allow for that by ensuring your basic API is sufficiently open and flexible (i.e. supports introspection) that such functionality can be built on top of it, rather than trying to include such convenience features in the core engine. Otherwise you'll end up in the same bind as the traditional macro-style engines of endless feature creep and API complexity as it tries to be all things to all men.
I am thinking about starting a blog on my hobbie. I have been collecting flags for many years and have a lot of great information. At first, I was going to start a website, but that looked to hard. Your blog helped. Thanks.
Hey
peter Hunt's ur personal blog is quite interesting.
Data entry
I do not like ElementTree. You can't even search for nodes based on element attributes. The Perl module of similar functionality, HTML::TreeBuilder, has had such functionality forever.