I am looking for a list of available methods for the 'tree' tag, particularly those for the branches attribute. The DTML guide lists two: 'tpValues' as the default, 'and objectValues' in the example. Are there any others? Michael.
On Tue, 2 Feb 1999, Michael Bernstein wrote:
I am looking for a list of available methods for the 'tree' tag, particularly those for the branches attribute.
The DTML guide lists two: 'tpValues' as the default, 'and objectValues' in the example.
Are there any others?
I suppose any Folder method that returns a list of objects/subobjects will do, even a user defined method that can filter which subobjects to include for example. Haven't test it though. Pavlos
Pavlos Christoforou wrote:
I suppose any Folder method that returns a list of objects/subobjects will do, even a user defined method that can filter which subobjects to include for example. Haven't test it though.
Yes, a user defined method can be used, but examining the list of methods for Folder objects reveals no 'tpValues' method. So I was wondering if there were other built-in methods (specific to tree) that are also unlisted in the guides. Michael.
Just a quickie note... I've begun doing some XML processing using the xml-sig's xml library and Z Templates. Specifically, walking a DOM tree in ZTML. Just demo stuff so far, like: <!--#var standard_html_header--> <!--#with firstChild--> <PRE><!--#in childNodes -->'<!--#var tagName-->' Node: "<!--#var toxml html_quote-->" <!--#/in--></PRE> <!--#/with--> <!--#var standard_html_footer--> The only Python I had to write in order to integrate XML objects with my framework was: from xml.sax.saxexts import make_parser from xml.dom.sax_builder import SaxBuilder _parser = make_parser() def xml_loader_(filename,**kwargs): h = SaxBuilder() _parser.setDocumentHandler( h ) _parser.parseFile( open(filename,'r') ) return h.document xml_classinfo_ = None,xml_loader_ I imagine integration with Zope would be a bit more complex, but not because of the XML aspects. I may take a whack at making an XMLDocument product for Zope when I have some spare time, if nobody else is currently working on one.
"Phillip J. Eby" wrote:
Just a quickie note... I've begun doing some XML processing using the xml-sig's xml library and Z Templates. Specifically, walking a DOM tree in ZTML. Just demo stuff so far, like:
<!--#var standard_html_header--> <!--#with firstChild--> <PRE><!--#in childNodes -->'<!--#var tagName-->' Node: "<!--#var toxml html_quote-->" <!--#/in--></PRE> <!--#/with--> <!--#var standard_html_footer-->
The only Python I had to write in order to integrate XML objects with my framework was:
from xml.sax.saxexts import make_parser from xml.dom.sax_builder import SaxBuilder
_parser = make_parser()
def xml_loader_(filename,**kwargs): h = SaxBuilder() _parser.setDocumentHandler( h ) _parser.parseFile( open(filename,'r') ) return h.document
xml_classinfo_ = None,xml_loader_
I imagine integration with Zope would be a bit more complex, but not because of the XML aspects. I may take a whack at making an XMLDocument product for Zope when I have some spare time, if nobody else is currently working on one.
Its really simple -- I've done a little bit in this direciton. I was trying to build a "browseable" XML tree (ie, create a DOM tree from an XML file and then use the <!--#tree--> contstruct to browse it "interactively"), but I couldn't fight through all of the tree functionality and gave up on it. On the xml-sig list, someone mentioned they had a XSL (tree construction part only -- the important part) engine in python. I would like to see an app where you can "try on" different XSL stylesheets for a given XML file, and then let you publish the XML through the various XSL stylesheets depending on URL (or something like that). Twould be nice to have the following absrtactins: 1) An XMLSource (normally, this would simply be an object which holds XML data -- but it could be a client for an XML-producing application, or a wrapper for a SQL query that creates an XML document on thefly, or so on). Would provide functions like "getContent()" or perhaps even a XPointer-dereferencer (ie get the first sibling of the last <blah> element, or whatever). Should also have a "changedSince(time)" function so that if the XMLSource content is updated, an application (or DTML code) can detect this and rerender. 2) A list of XSL stylesheets through which you present the XML obtained from the XMLSource 3) An XML source browser - pretty printing, expandable subtrees, etc. 4) XML validation (against a DTD stored in the product, or referred to by a URL or something similar) ** and for fun -- stuff that is not Zope-specific ** 5) Rudimentary XML editing 6) Forms-based XML editing 7) Some sort of way for expressing integrity and relational rules for entering information into XML documents, so you could easily build business rules on top of simple or more complex XML documents The reason I mention 5,6,7 is to keep these things in mind when developing XML products for Zope (and because Zope can address user interface issues). -Gabe, who'd do it all himself if he had time ;-)
I also thought of this: It would be nice to be able to have XML document refer to each other (via external entity references) as though they existed in a filesystem with the same directory structure as the Zope environment. That is, if doc1.xml is /xml/examples/dox1.xml and doc1.xml has <!ENTTTY other SYSTEM "../include/other.xml"> and uses &other;, then it would be kewl to have the file other.xml exist in /xml/include/other.xml The reason I say this would be cool is that you could develop an entire "web site" in XML and rely upon XSL (if you so chose) to convert it to HTML for presentation. And of course, the XML source can be an SQL query, or the product of some external program. I'm not sure if this is cool for kewlness's sake, or whether it makes a lot of sense to do.. I'm sure someone can think of a real good use for this. How hard would to do this? Donno. Don't know if its even possible unless you hack the xml-0.5 code. -Gabe P.S. You could do cool things if you made non-trivial XMLSource objects -- ie you could theoretically build an entire app on a complicated XMLSource that took URLs as a parameter, parsed that query, sent a request to some other server which spoke XML, got a result back, and composed that result content into XML for you, which could then be presented as HTML (if neccesary). More likely is the static site that is generated by a set of parameters given to the XMLSource which essentially "builds the site" for you. Other ideas?
At 02:26 PM 2/2/99 -0800, Gabe Wachob wrote:
I also thought of this:
It would be nice to be able to have XML document refer to each other (via external entity references) as though they existed in a filesystem with the same directory structure as the Zope environment. That is, if doc1.xml is /xml/examples/dox1.xml
Whoa, dude... I know just barely more than nothing about XML. I just think it's sort of a cool data format for certain kinds of structured documents. My main interest at the moment is a ZTML-friendly API for the DOM. It's annoying to have to do <!--#var "attributes['TITLE'].value"-->, for example, when what you want is to just say <!--#var TITLE--> and be done with it... or <!--#in ITEM_elements--> to iterate over sub-elements named ITEM. A quickie class to do this, which I've just got finished testing: class DOM_Browser(Acquisition.Implicit): """Wrapper for DOM objects""" node_elems = { 'documentElement':1,'firstChild':1,'lastChild':1,'parentNode':1, 'previousSibling':1,'nextSibling':1,'ownerDocument':1,'childNodes':2 } def __init__(self,node): self.__node__ = node def __getattr__(self,attr): n = self.__node__ atype=self.node_elems.get(attr,0) if atype==1: return self.__class__(getattr(n,attr)) elif atype==2: return map(self.__class__,getattr(n,attr)) else: try: return getattr(n,attr) except AttributeError: a = n.attributes if a is not None and a.has_key(attr): return a[attr].value if attr[-9:]=='_elements': if attr=='all_elements': return map(self.__class__,filter(lambda q: hasattr(q,'tagName'),n.childNodes)) else: return map(self.__class__,filter(lambda q,a=attr[:-9]: hasattr(q,'tagName') and a==q.tagName==a,n.childNodes)) raise AttributeError,attr def __getitem__(self,item): return self.__node__[item] def __str__(self): return self.__node__.toxml() And now by having my XML loader return DOM_Browser(document), I can write things like: <!--#with newsletter.newsletter_elements--> Headlines for Issue #<!--#var issue_num-->: <!--#in item_elements--><!--#var title--> <!--#/in--> <!--#/with--> and call it on XML that looks like: <newsletter issue_num="1"> <item title="The world is made of green cheese!">Yeah, right.</item> <item title="DOM_Browser rocks!">Awesome.</item> </newsletter> And get: Headlines for Issue #1: The world is made of green cheese! DOM_Browser rocks!
At 11:29 AM 2/2/99 -0800, Michael Bernstein wrote:
I am looking for a list of available methods for the 'tree' tag, particularly those for the branches attribute.
The DTML guide lists two: 'tpValues' as the default, 'and objectValues' in the example.
Are there any others?
Sure, but let me take the long route to answering this question. The tree tag is a generic device to display hierarchical data. You can use the tree tag to display arbitrary Python objects. Folders and Documents are only two choices of things to display. The DTML Guide gives a good explanation of the tree tag: http://www.zope.org/Documentation/Guides/DTML/ Here's the URL of the relevant section of the DTML guide: http://www.zope.org/Documentation/Guides/DTML/DTML-HTML/DTML.html#pgfId-1011 006 As it says, the branches attribute can be used to call different methods to determine the object's sub-objects. The default method for this is 'tpValues'. To work with the tree tag, the Python objects must adhere to the tree protocol. From lib/python/TreeDisplay/TreeItem.py here's the basic tree protocol: class TreeProtocol: def tpValues(self): """Return the immediate subobjects of the current object that should be shown in the tree. """ def tpId(self): """Return a value to be used as an id in tree state.""" def tpURL(self): """Return string to be used as URL relative to parent. The tree tag accumulates the tpURL of objects as it traverses the tree. At any given point during dtml rendering within the tree tag, you can use:: <!--#var tree-item-url--> to get the url up to the point of the current object being rendered. """ Since we can specify alternates to 'tpValues' in the tree tag, your Python objects only really need to support the 'tpId' and 'tpURL' methods, you can name your sub-object generating method something besides 'tpValues', if you want. So to get back to your original question, depending on what sort of objects you are displaying with the tree tag, you can specify any appropriate method of the objects as the 'branches' method, so long as it returns a list of sub-objects. In the case of folderish Zope objects, 'objectValues' is probably the most appropriate method, since it returns a list of Zope sub-objects. The 'tpValues' method of Zope Folders return a list of sub-Folders, which is used to generate the familiar tree in the left frame of the management screen. However, there is nothing stopping you from defining new methods with for example External Methods, to return your own choice of sub-objects. For example, here's an External Method that just returns a Folder's sub-Documents and sub-Folders: def subFoldersAndDocuments(self): "return my sub-folders and sub-documents" return self.objectValues(['Folder','Document']) Say you call this External Method 'myObjectValues' and define it at the top of your Zope object hierarchy. Now all Zope objects will acquire it, and you can use it as a branches method: <!--#tree branches=myObjectValues--> <!--#var id--> <!--#/tree--> This will display the folders and documents in your object hierarchy as a tree. But the sky's the limit! It really gets interesting when Documents get properties (coming very soon!). Then you might want to mark public documents with a property, say 'Visible', and use a slightly different branches method, for example: def visibleObjects(self): "return my visible sub-documents and folders" result=[] for object in self.objectValues(['Document','Folder']): if hasattr(object,'Visible') and object.Visible: result.append(object) return result As you can see (I hope ;-) this method returns a filtered list of sub-documents and sub-folders. I hope this helps. The tree tag can do some pretty powerful stuff, if you work with it. -Amos
Amos Latteier wrote:
def tpId(self): """Return a value to be used as an id in tree state."""
I've had some problems relating to the tpId() method. Can somebody help sort this out? After staring at the HTML source for a DTML tree, I eventually realized that tpId()'s return value is used as an HTML "internal" anchor (waddayacallit, it's referenced by <A HREF="doc#anchor">...</A>). So it needs to return a string which makes a valid HTML anchor. The HTML generated for a tree node looks something like this: <TR> <TD WIDTH="16" VALIGN="TOP"><A NAME="someTpIdValue"><A HREF="index_html?tree-e=eJyLVvfMKy5JzMlJLMnMz1MISi3ILyopVtdRUPd3VPArzU1KLVIwUNBwTy3KTcxTcEnMy0zNKdZUjwUAJQAStg#someTpIdValue"><IMG SRC="/cgi-bin/myapp/p_/pl" BORDER=0></A></TD> <TD VALIGN="TOP" ALLIGN="LEFT"> some text </TD> </TR> Problems: There's no close tag for the anchor (or for the hyperlink, depending on your point of view). 'ALLIGN' should be 'ALIGN'. The second problem is no big deal, but the first one has bad consequences: If I use a valid anchor name, then when I click on a tree node (using Netscape Navigator 4.x), nothing happens. But if I change tpId() to return an invalid anchor name (e.g. something containing blanks or parentheses), then when I click on a tree node it expands and contracts as expected. What am I doing wrong? (Lemme know if you need to see code.) Thanks for any help. -- Mitch Chapman | 4105 Executive Drive Ohio Electronic Engravers, Inc. | Beavercreek, OH 45430 mchapman@oee.com | import StandardDisclaimer
Mitch Chapman wrote:
Amos Latteier wrote:
def tpId(self): """Return a value to be used as an id in tree state."""
I've had some problems relating to the tpId() method. Can somebody help sort this out?
After staring at the HTML source for a DTML tree, I eventually realized that tpId()'s return value is used as an HTML "internal" anchor (waddayacallit, it's referenced by <A HREF="doc#anchor">...</A>). So it needs to return a string which makes a valid HTML anchor.
Hm. Good point. The use as an anchor is really secondary. The main purpose of the id is to uniquely identify an object within a tree (or maybe within a branch). The object ids are stored in the tree data cookies to keep track of which branches are expanded. For this reason, the ids should be small. Note that you don't have to define tpId. If it is undefined, then the persistent id (_p_oid) is used if the object is persistent and the Python id will be used if it isn't. Also note that the id is really only needed for expandable objects (objects whose tpValues returns a non-empty list. Finally note that use can use the tag attribute, id, to specify a different method to get an id. (You can also use the url attribute to specify a method other than tpURL.) Sigh. I need to update the tree tag section in the DTML manual.
The HTML generated for a tree node looks something like this:
<TR> <TD WIDTH="16" VALIGN="TOP"><A NAME="someTpIdValue"><A HREF="index_html?tree-e=eJyLVvfMKy5JzMlJLMnMz1MISi3ILyopVtdRUPd3VPArzU1KLVIwUNBwTy3KTcxTcEnMy0zNKdZUjwUAJQAStg#someTpIdValue"><IMG SRC="/cgi-bin/myapp/p_/pl" BORDER=0></A></TD> <TD VALIGN="TOP" ALLIGN="LEFT"> some text </TD> </TR>
Problems: There's no close tag for the anchor (or for the hyperlink, depending on your point of view).
OK, this'll be fixed in the 1.10 release.
'ALLIGN' should be 'ALIGN'.
Hm. The source looks OK here. Someone must've already fixed this. Jim -- Jim Fulton mailto:jim@digicool.com Technical Director (888) 344-4332 Python Powered! Digital Creations http://www.digicool.com http://www.python.org Under US Code Title 47, Sec.227(b)(1)(C), Sec.227(a)(2)(B) This email address may not be added to any commercial mail list with out my permission. Violation of my privacy with advertising or SPAM will result in a suit for a MINIMUM of $500 damages/incident, $1500 for repeats.
Jim Fulton wrote:
Note that you don't have to define tpId. If it is undefined, then the persistent id (_p_oid) is used if the object is persistent and the Python id will be used if it isn't.
I shot myself in the foot on this one. Early on I came across Zope's TreeItem.TreeProtocol class, and decided to use it as a mixin. Of course TreeProtocol is a protocol specification, and its tpId method doesn't return anything. So I browsed around to see how it was used. After concluding that tpId served as an anchor name, I tried returning id(self). (It's a valid anchor name, and it's unique.) At which point tree nodes stopped expanding when clicked. So I looked at TreeTag.py, saw *it* using Python object IDs -- and working -- and decided it was time for beer. There's a moral here, and someone less addle-brained could state it clearly. Here's my attempt: In Python, protocol specs aren't gospel. The client framework may, like TreeTag.py, be able to adapt if you don't conform strictly to the protocol. Or how about: Think twice before mixing in a protocol class. -- Mitch Chapman | 4105 Executive Drive Ohio Electronic Engravers, Inc. | Beavercreek, OH 45430 mchapman@oee.com | import StandardDisclaimer
On Tue, 2 Feb 1999, Amos Latteier wrote:
def tpURL(self): """Return string to be used as URL relative to parent. The tree tag accumulates the tpURL of objects as it traverses the tree. At any given point during dtml rendering within the tree tag, you can use:: <!--#var tree-item-url--> to get the url up to the point of the current object being rendered. """
I had the same problem with Michael in designing a global navigation side margin. If the tree tag is used in a different frame like the Zope management screens then all is well, because the frame always refers to the same URL. If however one decides to use tables to create the global side margin then the context in which the global side margin method is called becomes important. Before Pricipia was open sourced my TinyZope module had a similar BaseClass to Zope's Folder which computed and set the absolute URL of any object added in that folder. It was easy then to construct Global navigation aids, but with Zope I can not see a simple clean way of doing it unless someone uses ZClient to call the relevant method. Pavlos
Pavlos Christoforou wrote:
On Tue, 2 Feb 1999, Amos Latteier wrote:
def tpURL(self): """Return string to be used as URL relative to parent. The tree tag accumulates the tpURL of objects as it traverses the tree. At any given point during dtml rendering within the tree tag, you can use:: <!--#var tree-item-url--> to get the url up to the point of the current object being rendered. """
I had the same problem with Michael in designing a global navigation side margin. If the tree tag is used in a different frame like the Zope management screens then all is well, because the frame always refers to the same URL. <STUFF DELETED>....which computed and set the absolute URL of any object added in that folder. It was easy then to construct Global navigation aids, but with Zope I can not see a simple clean way of doing it unless someone uses ZClient to call the relevant method.
I haven't addressed the absolute URL problem since it was covered in a previous thread about images. I am including Jim Fultons thoughts on this for those of you who hadn't seen the previous thread: On Dec. 8th 1998 Jim Fulton said:
I'm going to try to respond to the entire thread at once by simply stating my position on how this should work. Here goes:
1. Images, and perhaps all objects, should have a method named something like absoluteURL, that returns some kind of absolute URL. <STUFF DELETED> 2. The str for an image will use absoluteURL and will use size methods too, if there every are any.
3. There may be lots of other image methods that could be used with fmt, as in:
<!--#var "images.logo" fmt="relative"-->
Jim
I take this to mean that if 'context' and 'absoluteURL' are both added to Zope, flexible global navigation of the sort we've been discussing will become possible. Michael.
Pavlos Christoforou wrote:
On Tue, 2 Feb 1999, Amos Latteier wrote:
def tpURL(self): """Return string to be used as URL relative to parent. The tree tag accumulates the tpURL of objects as it traverses the tree. At any given point during dtml rendering within the tree tag, you can use:: <!--#var tree-item-url--> to get the url up to the point of the current object being rendered. """
I had the same problem with Michael in designing a global navigation side margin. If the tree tag is used in a different frame like the Zope management screens then all is well, because the frame always refers to the same URL. If however one decides to use tables to create the global side margin then the context in which the global side margin method is called becomes important.
So what? Should relative URLs still be correct? I guess that what you want is absolute URLs that (mostly) don't depend on context.
Before Pricipia was open sourced my TinyZope module had a similar BaseClass to Zope's Folder which computed and set the absolute URL of any object added in that folder. It was easy then to construct Global navigation aids, but with Zope I can not see a simple clean way of doing it unless someone uses ZClient to call the relevant method.
I'm not sure what ZClient has to do with it. I guess you want a navigation bar in a standard header or footer that provides absolute URL to some standard places that don't depend on where you are. Right? I think that the 1.10 absolute URL machinery (absolute_url method defined in SimpleItem.Item and therefore in all framework objects) should make this alot easier. We'll put together a demonstration of this. Jim -- Jim Fulton mailto:jim@digicool.com Technical Director (888) 344-4332 Python Powered! Digital Creations http://www.digicool.com http://www.python.org Under US Code Title 47, Sec.227(b)(1)(C), Sec.227(a)(2)(B) This email address may not be added to any commercial mail list with out my permission. Violation of my privacy with advertising or SPAM will result in a suit for a MINIMUM of $500 damages/incident, $1500 for repeats.
On Wed, 3 Feb 1999, Jim Fulton wrote:
I guess you want a navigation bar in a standard header or footer that provides absolute URL to some standard places that don't depend on where you are. Right? I think that
that's exactly right.
the 1.10 absolute URL machinery (absolute_url method defined in SimpleItem.Item and therefore in all framework objects) should make this alot easier. We'll put together a demonstration of this.
That's really good news. Thanks Pavlos
participants (7)
-
Amos Latteier -
Gabe Wachob -
Jim Fulton -
Michael Bernstein -
Mitch Chapman -
Pavlos Christoforou -
Phillip J. Eby