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 tag | Close tag | Attributes | Docstring 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:
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>
<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>
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')"/>
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']
xp:session('mydict', 'mysubdict', 'myvalue')
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 layoutdef myfunction(dummy, value): return 'Hello with %s' % value def myfunction2(dummy, value1, value2): return 'Hello again with %s in %s' % (value1, value2)
self.xsl(... , functions=[myfunction, myfunction2])
<xsl:value-of select="xp:myfunction('Xierpa')"/>
<xsl:value-of select="xp:myfunction2('Xierpa', 'Python')"/>
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"/>
<?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 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"/>
