XSLT: Difference between revisions
Line 1,069: | Line 1,069: | ||
</source> |
</source> |
||
|} |
|} |
||
=== Example recursive function === |
|||
<source lang=xslt> |
|||
<xsl:template name="escape"> |
|||
<xsl:param name="content"/> |
|||
<xsl:if test="string-length($content)>0"> |
|||
<xsl:choose> |
|||
<xsl:when test="starts-with($content,'(')"><xsl:text>\(</xsl:text><xsl:call-template name="escapeForMake"><xsl:with-param name="content" select="substring($content, 2)"/></xsl:call-template></xsl:when> |
|||
<xsl:when test="starts-with($content,')')"><xsl:text>\)</xsl:text><xsl:call-template name="escapeForMake"><xsl:with-param name="content" select="substring($content, 2)"/></xsl:call-template></xsl:when> |
|||
<xsl:when test="starts-with($content,'\')"><xsl:text>\\</xsl:text><xsl:call-template name="escapeForMake"><xsl:with-param name="content" select="substring($content, 2)"/></xsl:call-template></xsl:when> |
|||
<xsl:otherwise> |
|||
<xsl:value-of select="substring($content,1,1)"/> |
|||
<xsl:call-template name="escapeForMake"> |
|||
<xsl:with-param name="content" select="substring($content, 2)"/> |
|||
</xsl:call-template> |
|||
</xsl:otherwise> |
|||
</xsl:choose> |
|||
</xsl:if> |
|||
</xsl:template> |
|||
</source> |
|||
Call it as follow: |
|||
<source lang=xslt> |
|||
<xsl:call-template name="escape"><xsl:with-param name="content"> select="@synopsis" /></xsl:call-template> |
|||
</source> |
|||
Note that the same template could be implemented using string extension: |
|||
<source lang=xslt> |
|||
<?xml version="1.0"?> |
|||
<xsl:stylesheet |
|||
version="1.0" |
|||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" |
|||
xmlns:func="http://exslt.org/functions" |
|||
xmlns:exsl="http://exslt.org/common" |
|||
xmlns:str="http://exslt.org/strings" |
|||
extension-element-prefixes="func" |
|||
xmlns:my="http://myserver.org/xsl/functions" |
|||
exclude-result-prefixes="exsl str func my"> |
|||
<func:function name="my:escape"> |
|||
<xsl:param name="filename" /> |
|||
<func:result> |
|||
<xsl:value-of select="str:replace(str:replace(str:replace(.,'\','\\'),'(','\('),')','\)')" /> |
|||
</func:result> |
|||
</func:function> |
|||
<xsl:template match="file"> |
|||
<directory><xsl:value-of select="my:escape()"/></directory> |
|||
</xsl:template> |
|||
</xsl:stylesheet> |
|||
</source> |
|||
== Miscellaneous == |
== Miscellaneous == |
Revision as of 17:43, 14 December 2016
XSLT stands for Extensible Stylesheet Language Transformations.
Links
- Gnome library
- exslt (extensions)
- Extensions supported in libxml (
xsltproc
processor)
Overview
Currently there are two versions of the XSLT standards: XSLT 1.0 and XSLT 2.0.
- XSLT 1.0
- On linux, the standard XSLT 1.0 processor is
xsltproc
(from package xsltproc, libxml2 library). - In XSLT 1.0, most functions come from XSLT extensions (like http://exslt.org/).
- XSLT 2.0
- On linux, the standard XSLT 2.0 processor is
saxonb-xslt
(from package libsaxonb-java). - XSLT 2.0 introduces XQuery, XPath 2.0, and XSLT functions (with prefix
fn:
). See here for a detailed list of features.
Extensions
From w3.org [1]:
- The element extension mechanism allows namespaces to be designated as extension namespaces. When a namespace is designated as an extension namespace and an element with a name from that namespace occurs in a template, then the element is treated as an instruction rather than as a literal result element.
Extensions available in the XSLT processor
Using xsltproc (package xsltproc [2], we can get the list of built-in extensions with:
xsltproc --dumpextensions
# Registered XSLT Extensions
# --------------------------
# Registered Extension Functions:
# {http://exslt.org/math}atan2
# {http://exslt.org/strings}align
# ...
- exslt.org/crypto
- "Hidden" extensions that provides basic crypto functions (apparently from patch [3], introduced in July 5 2004 [4])
- See also [5]
- CAUTION — These extensions are not available if using a custom implementation of Python like Anaconda
xsltproc --dumpextensions|grep crypto
# {http://exslt.org/crypto}rc4_decrypt
# {http://exslt.org/crypto}md4
# {http://exslt.org/crypto}sha1
# {http://exslt.org/crypto}md5
# {http://exslt.org/crypto}rc4_encrypt
- Example of use:
<xsl:template match="rootnode">
<xsl:value-of select="crypto:md5('ahahah')"/>
</xsl:template>
Quick reference
Minimal stylesheet
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
</xsl:stylesheet>
This is the minimal stylesheet. Another solution is to use an xsl:transform
element, which is a synonym to xsl:stylesheet
[6].
<?xml version="1.0"?>
<books>
<book>
<title>XML in a Nutshell</title>
<editor>O'Reilly</editor>
</book>
<book>
<title>XSL in a Nutshell</title>
<editor>O'Reilly</editor>
</book>
</book>
When applied to the example XML file above (with xsltproc minimal.xsl example.xml
), the minimal stylesheet produces this result:
<?xml version="1.0"?>
XML in a Nutshell
O'Reilly
XSL in a Nutshell
O'Reilly
The result is not empty. This is because by default XSLT has a default template for text node that simply copy the content of the node without transform.
xsl:attribute
Input | Output |
---|---|
<link site="www.stackoverflow.com"/>
|
<a href="http://www.stackoverflow.com">Click here</a>
|
Use
<xsl:template match="link">
<a>
<xsl:attribute name="href">
<xsl:text>http://</xsl:text><xsl:value-of select="@site"/>
</xsl:attribute>
<xsl:text>Link</xsl:text>
</a>
</xsl:template>
Or shorter using curly braces {...}
[7]:
<xsl:template match="link">
<a href="http://{@site}">Click here</a>
</xsl:template>
Also for:
- Using variables (like in
<a href="http://{$varName}">Click here</a>
)
func:functions
References:
Using the exslt:func extension, we can define functions in XSLT 1.0.
Here an example stylesheet:
<?xml version="1.0"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:func="http://exslt.org/functions"
xmlns:exsl="http://exslt.org/common"
xmlns:str="http://exslt.org/strings"
xmlns:my="http://myserver.org/xsl/functions"
extension-element-prefixes="func"
exclude-result-prefixes="exsl str func my">
<func:function name="my:dirname">
<xsl:param name="filename" />
<func:result>
<xsl:for-each select="exsl:node-set(str:tokenize(.,'/'))">
<xsl:if test="(position()!=1) and (position()!=last())">/</xsl:if>
<xsl:if test="position()!=last()"><xsl:value-of select="."/></xsl:if>
</xsl:for-each>
</func:result>
</func:function>
<xsl:template match="file">
<directory><xsl:value-of select="my:dirname(.)"/></directory>
</xsl:template>
</xsl:stylesheet>
|
<?xml version="1.0"?>
<root>
<file>your/dir/file.ext</file>
<file>more/directory/with space/dir/file.ext</file>
<file>file.ext</file>
<file></file>
</root>
|
We get the following result (xsltproc style.xsl data.xml
):
<?xml version="1.0"?>
<directory>your/dir</directory>
<directory>more/directory/with space/dir</directory>
<directory/>
<directory/>
Some remarks:
extension-element-prefixes="func"
is mandatory, or xsltproc will complain with meaning less errors like:
{http://myserver.org/xsl/functions}dirname: called with too many arguments xsltApplySequenceConstructor: param was not compiled xsltApplySequenceConstructor: for-each was not compiled
Tips
Output tags like <?fileVersion 4.0.0 ?>
Use a xsl:text
tag with attribute disable-output-escaping="yes"
: [8]:
<xsl:template match="/">
<xsl:text disable-output-escaping="yes"><?fileVersion 4.0.0?></xsl:text>
</xsl:template>
This will produce:
<?fileVersion 4.0.0?>
Generate a random UID
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:data="http://exslt.org/dates-and-times"
xmlns:math="http://exslt.org/math"
extension-element-prefixes="date math"
version='1.0'>
<!-- .... -->
<xsl:variable name="noncels" select="floor(math:random()*800)+100"/>
<xsl:variable name="noncems" select="data:seconds(date:date-time())-date:seconds('1970-01-01T00:00:00')"/>
<!-- .... -->
<xsl:value-of select="concat($noncems,noncels+0)"/>
</xsl:stylesheet>
Beautify / indent an XML file
Use the identity transform: [9]
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:transform>
Examples
Simple <xsl:template>
This template will replace 'project' by a simple text
|
Spaces and CR
CR/spaces are preserved...
inside 'xsl:text'. But spaces/CR between two tags are deleted.
Except if ...
it contains non-blanks.
So better use empty text tags to eat spaces/CR, while still using
... xslt parameters.
|
Using entities
Use entities for special characters like
carriage return
or " space " where normal "space" or
carriage return
does not work.
Using entities is also shorter than using 'xsl:value-of' tags.
|
Using template parameters
Calling template by matching, passing a string:
parameter is a string
Calling template by matching, passing a GLOBALPARAM:
parameter is global param
Calling template by name
parameter is a string
|
Simple <xsl-apply-templates>
and .
dot is 'content1', dot is 'content2', dot is 'content3',
|
Example of <xsl:for-each>
Simple for-each loop:
dot is 'content1', dot is 'content2', dot is 'content3',
For-each loop with select condition:
double,
|
Example of <xsl:choose>
We have content1 for small.
We have CONTENT2 for big.
We have content3 for small.
|
Template with match rule and dynamic entity
small
big
small
|
More complex apply-templates, with dynamic entities
smallbigsmall
|
Using namespace
SMALL BIG SMALL
|
Example of expressions
<?xml version="1.0" encoding="UTF-8"?>
<p>
<msg>dot is current tag content, here '.' is 'content1'</msg>
<msg attr="content1">Use braces {...} in attributes</msg>
<msg random="unique.799522789">{...} can be any expression</msg>
</p><p>
<msg>dot is current tag content, here '.' is 'content2'</msg>
<msg attr="content2">Use braces {...} in attributes</msg>
<msg random="unique.90206728">{...} can be any expression</msg>
</p><p>
<msg>dot is current tag content, here '.' is 'content3'</msg>
<msg attr="content3">Use braces {...} in attributes</msg>
<msg random="unique.2005052793">{...} can be any expression</msg>
</p>
|
Generate custom XML tags
<?xml version="1.0" encoding="UTF-8"?>
<?fileVersion 4.0.0?><cproject id="my project"/><p>Use 'disable-output-escaping' to generate xml tags.</p>
|
Removing white spaces
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project>
<cleaned_target>no_space_at_all</cleaned_target>
<cleaned_target>with_space_around</cleaned_target>
<cleaned_target>with carriage returns</cleaned_target>
<cleaned_target>with spaces between the words</cleaned_target>
</project>
|
Two-stage xml using variables and node-set
<?xml version="1.0"?>
<p>XML in a Nutshell</p>
<p>XSL for the Noobs</p>
|
Using call-template
<?xml version="1.0"?>
<p>abcdef</p>
|
Example recursive function
<xsl:template name="escape">
<xsl:param name="content"/>
<xsl:if test="string-length($content)>0">
<xsl:choose>
<xsl:when test="starts-with($content,'(')"><xsl:text>\(</xsl:text><xsl:call-template name="escapeForMake"><xsl:with-param name="content" select="substring($content, 2)"/></xsl:call-template></xsl:when>
<xsl:when test="starts-with($content,')')"><xsl:text>\)</xsl:text><xsl:call-template name="escapeForMake"><xsl:with-param name="content" select="substring($content, 2)"/></xsl:call-template></xsl:when>
<xsl:when test="starts-with($content,'\')"><xsl:text>\\</xsl:text><xsl:call-template name="escapeForMake"><xsl:with-param name="content" select="substring($content, 2)"/></xsl:call-template></xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring($content,1,1)"/>
<xsl:call-template name="escapeForMake">
<xsl:with-param name="content" select="substring($content, 2)"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
Call it as follow:
<xsl:call-template name="escape"><xsl:with-param name="content"> select="@synopsis" /></xsl:call-template>
Note that the same template could be implemented using string extension:
<?xml version="1.0"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:func="http://exslt.org/functions"
xmlns:exsl="http://exslt.org/common"
xmlns:str="http://exslt.org/strings"
extension-element-prefixes="func"
xmlns:my="http://myserver.org/xsl/functions"
exclude-result-prefixes="exsl str func my">
<func:function name="my:escape">
<xsl:param name="filename" />
<func:result>
<xsl:value-of select="str:replace(str:replace(str:replace(.,'\','\\'),'(','\('),')','\)')" />
</func:result>
</func:function>
<xsl:template match="file">
<directory><xsl:value-of select="my:escape()"/></directory>
</xsl:template>
</xsl:stylesheet>
Miscellaneous
<xsl:param name="MYPARAM">
in<xsl:stylesheet>
node declares a global parameter.
- After this declaration we can use
$MYPARAM
to get the value of the parameter. If it is not declared, we can only use$MYPARAM
if it is passed as a parameter (e.g. via command linexsltproc -param MYPARAM "'myparamvalu'"
), otherwise an error is triggered.