Welcome to Xierpa. This is the stable 1.2 version which was developed by Petr van Blokland + Claudia Mens (buro@petr.com) and is maintained by Michiel Kauw-A-Tjoe. It is subclassed by the Museum Meermanno and American Express applications.

XsltBuilder

The XsltBuilder class is a parser for XML and XSL documents.
The XML output tree is interpreted by Python. This will cause all output tag be interpreted by Python builder methods. This way it is possible (by translating or copying the XML tags) to use Python methods as tag names. Also the attributes are automatically converted into Python values. Currently the following types are recognized (through the transformers tool xmlattr2pyattr): int, long, float or boolean (represented by one of 'TRUE', True, true, FALSE, False, false) and Python syntax strings for dict, list and tuple.

Another consideration is that is ambiguous for the XSL parser to translate the XML tags into either tags with a block and tags without. The problem does arise when identical tags directly follow each other, since then there is a tag on the stack with the same name. To avoid this ambiguity, Python tags that don’t need a block should have a different name, following the naming convention in XML (replacing the “/” by a “_”):
Open Close Compact
<tagname> </tagname> <tagname/>
tagname(...) _tagname(...) tagname_(...)

An overview

The XsltBuilder class contains the following tags:
Open tagClose tagAttributesDocstring or default value
DEBUG False
editxml copyunknown
debug
functions
gstate
h
nocache
params
path
python
src
template
w
The edit opens an editor on either the content of the src file or the content text. If e.form['edit'] is 1 then add an edit button to all texts on the page marked by this edit tag. If the value of e.form['edit'] is equal to the path name of a tag, then build a textarea with the defined text and add a savebutton. When saved, the application should must check on any save actions, using the e.form['xierpa_command' to check on a “Save” command and the e.form['editxml_path'] and e.form['editxml_content'] for respectively the path and the source of the saved file.
In case the editxml is used inside a LayoutBuilder, then the gstate parameter can be used to pass information about the current column width. The tag calculates an estimate from pixels to characters for the cols value of the HTML textarea attribute. Then the row is estimated from the total amount of character in the content file.
See also: self.xml

Python example
self.edit(src='./_m/mymodule.xml', gstate=gstate, template=TEMPLATEPATH)


getxml2xml addheader
addroot
catchexception
copyunknown
debug
functions
nocache
onerrorescapexml
python
src
tailhook
template
texthook
xml
The getxml2xml method derives the result output of self.xml(...) to a temporary buffer. After the XML transformation, the original self.result output buffer is restored and the temporary result is answered. Note that the method does not facilitate any protection against changing the content of e or e.session, so it is up to the application to take care of any side effects.
If the optional catchexception (default value is True) is set to False then the parser does not try to catch as parser error. This allows the calling application class to get a better view on the type of XML error.
If the optional onerrorescapexml (default value is False) is set to True then export the escaped XML if a parsing error occurs.


xml addheader
addroot
catchexception
checkunicode
copyunknown
debug
functions
nocache
onerrorescapexml
python
src
tailhook
template
texthook
xml
The xml tag transforms an XML string or file to another format, such as XHTML and then writes the result to the output, while using the file (with relative path template) as XSL template.
This gives the Xierpa developer a very powerful tool for XML text transformation to formats that can be used in a website.

Finally the Xierpa builder will try, for all nodes in the (binary) result tree, to call the Python methods in the running builder with the same name as the tag.
The xml tag thus allows subsequent translations (first XSL templates and the Python methods).
Python example
<example class="myclass">
...
</example>

will result in calling the builder as self with the following code:
Python example
self.example(class_='myclass')
...
self._example()

If the nocache attribute flag is True then always clear the XSL cache.
If the copyunknown attribute is True and the method of the open tag does not exist, then this tag is copied to the output. This enables to call Python tags to copy XHTML into the output. If the attribute is False (default) then an error message is written.
When closing the tag, test if it still is on the stack of opened tags. If so, the try to call the closing method of the tag. If that does not exist, copy it to the output (when copyunknown is True) or show the error message in the output.

Python example
<image src="./_images/myimage.png"/>

will result in calling the builder as self with the following equivalent code:
Python example
self.image(src="./_images/myimage.png")

and in case the tag is defined in the local class
Python example
<xyz name="myname" amount="123">
...
</xyz>>

is equivalent to
Python example
self.xyz(name='myname', amount=123)
...
self._xyz()

Note: The original amount string value is converted into an integer

Note: The reserved Python word for attribute class is automatically translated to class_.


The python attribute determines the output of the tree:

  • python=False
    The resulttree is copied to the output;
  • python=True
    Call back on Python methods with the same name as the tags, converting the attribute where possible to Python objects.
One of the two attributes xml or src is mandatory. The first can contain an XML string that will be interpreted. The latter is an relative path to a file containing an XML document.
The template attribute is an optional relative path to an XSL (1.0) document. If it is defined, then the XSL will be used for translating the XML. If the path is empty, then the XML tree is copied untranslated. Note in that case it is a common mistake to copy an untranslated head (as text heading) tag since it will corrupt the page being interpreted as XHTML tag.
If the addheader attribute is defined, then add a UTF-8 to the source content.
If the addroot attribute is defined, then add the root tag as defined by the attribute value.
To make sure that we don’t mix up string type, the xml attribute is checked to be unicode type.

If the texthook attribute is defined, then use that method to output all XML text. This allows the application to catch specific features of the output text such as white space or words, without changing the behaviour of the standard self.text(). If texthook is omitted, then the standard self.text is used instead.
Similarly the tail text of a node is send to output using the optional method defined by tailhook. If omitted then the optional method texthook is used and otherwise the standard self.text.

If the optional catchexception (default value is True) is set to False then the parser does not try to catch as parser error. This allows the calling application class to get a better view on the type of XML error.
If the optional onerrorescapexml (default value is False) is set to True then export the escaped XML if a parsing error occurs.

When the debug attribute flag is True, then print the result tree as source code

Todo: Caching of documents, checking them against modification times.
See also: http://codespeak.net/lxml, specific on the lxml Python library used.
See also: http://www.w3schools.com/xsl/xsl_languages.asp on XSL in general.

When the application is running under GoogleApp, then no XSLT/XML transformation is available. In that case the XML (XHTML in most cases) is answered untransformed.

Passing parameters to XSL

The only (?) disadvantage of the Xierpa implementation of start tags and end tags (e.g. body and _body) is that start and end tags do not have a notion of the enclosed “XML” block. Therefor it is not really possible to parse XML blocks conditionally in Python builder methods. Instead we can use XSL to parse the blocks and take the result into a Python parameter. E.g. a language tag <nl> needs the e.session['xierpa_language'] or the e.form['nl'] to test against. If the parameter fits, then the block of the tag is send to the output.

Therefor the XsltBuilder automatically makes the e, e.form and e.session objects available to the XSL template. Typically an XSL stylesheet the needs these parameters has to declare the Xierpa namespace as follows:
<xsl:stylesheet version="1.0" 
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	xmlns:xp="http://www.xierpa.com/xslt">
	...
</xsl:stylesheet>
A template that shows the current path then might look like this:
<xsl:stylesheet version="1.0" 
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	xmlns:xp="http://www.xierpa.com/xslt">

	<xsl:output method="xml"/>
	
	<xsl:template match="showpath">
		<xsl:value-of select="xp:e('path')"/>
	</xsl:template>
</xsl:stylesheet>
Notice that instead of a dictionary in Python, e is a function that take a key string to return the stored value. Similarly xp:form('myname') will answer a parameter value from the url named myname and xp:session('myname') will answer the related session value.

Similar the e.form and e.session values are automatically available in XPath as follows
<xsl:value-of select="xp:form('myformparameter')"/>
<xsl:value-of select="xp:session('mysessionparameter')"/>
showing respectively e.form['myformparameter'] and e.session['mysessionparameter'].

The behaviour of the XSL xp:session is somewhat special. Since we cannot directly address any lists or dictionaries inside the session (as we can in xpyth attributes), it is allowed to add more attributes to the session function. They will be interpreted as keys inside dictionaries or list in session values. So the Python equivalent of
e.session['mydict']['mysubdict']['myvalue']
is in XSL (assuming that all are dictionaries):
xp:session('mydict', 'mysubdict', 'myvalue')
If one of session variables is a plain value, then it is directly answered, no matter if there are unused parameters. If the value is a list then the Python in is used to answer a boolean value.

Expanding XSL/XPath

It is possible to add functions in XSL/XPyth with the functions of the xml attribute by adding a list of local functions. A typical function with one parameter has to have to layout
def myfunction(dummy, value):
	return 'Hello with %s' % value

def myfunction2(dummy, value1, value2):
	return 'Hello again with %s in %s' % (value1, value2)
with the XSL call
self.xsl(... , functions=[myfunction, myfunction2])
Now the functions can be called in XSL as follows
<xsl:value-of select="xp:myfunction('Xierpa')"/>
<xsl:value-of select="xp:myfunction2('Xierpa', 'Python')"/>
This will show in the output
Hello with Xierpa
Hello again with Xierpa in Python

Including XSL library templates

xierpa/unknown.xsl

We can use the “*” template to copy an XML tag to the output where it will call a Python builder method with the same name. This template is included by from the /_xsl/xierpa/unknown.xsl library XSL.
<xsl:include href="xierpa/unknown.xsl"/>

The source of the unknown template is implemented as follows:
<xsl:template match="*">
	<xsl:copy>
		<xsl:for-each select="@*">
			<xsl:copy/>
		</xsl:for-each>
		<xsl:apply-templates/>
	</xsl:copy>
</xsl:template>

This template also does copy the attributes of the tag to the output. The error template is also part of this library document.

Note that this wat the xp:e(), xp:form() and xp:session() functions can be overwritten, but this is not recommended.

xierpa/authorization.xsl

<xsl:include href="xierpa/authorization.xsl"/>
The current version (2007/10/01) looks something like this (see /_xsl/xierpa/authorization.xsl for the latest version:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	xmlns:xp="http://www.xierpa.com/xslt">

	<xsl:output method="xml"/>

	<xsl:template match="ifloggedin">
		<xsl:if test="xp:session('xierpa_user')">
			<xsl:apply-templates/>
		</xsl:if>
	</xsl:template>
	
	<xsl:template match="ifnotloggedin">
		<xsl:if test="not(xp:session('xierpa_user'))">
			<xsl:apply-templates/>
		</xsl:if>
	</xsl:template>
	
	<xsl:template match="ifauthorized">
		<!-- @role -->
		<xsl:value-of select="xp:session('xierpa_user_roles', @role)"/>
		<xsl:value-of select="@role"/>
		<xsl:if test="xp:session('xierpa_user_roles', @role)">
			<xsl:apply-templates/>
		</xsl:if>
	</xsl:template>
		
	<xsl:template match="ifnotauthorized">
		<!-- @role -->
		<xsl:if test="not(xp:session('xierpa_user_roles', @role))">
			<xsl:apply-templates/>
		</xsl:if>
	</xsl:template>
		
</xsl:stylesheet>
The ifloggedin and ifnotloggedin templates check on the existence of e.session['xierpa_user']. If the value exists (or not) then the block of the tag is rendered. Otherwise its content is ignored.
The ifauthorized and ifnotauthorized templates check if the role attribute value is in the list of roles as defined in e.session['xierpa_user_roles']. It is the responsibility of the Python application to put the right values in the session.

xierpa/link.xsl

<xsl:include href="xierpa/link.xsl"/>

xierpa/email.xsl

<xsl:include href="xierpa/email.xsl"/>

xierpa/language.xsl

<xsl:include href="xierpa/language.xsl"/>