Two/multi phases XSLT is very useful if you do have multiple steps to process your data. Here is an example.
I have a data dictionary to store authors:
<?xml version="1.0" encoding="UTF-8"?>
<authors>
<author>Allinson, J.</author>
<author>Feng, F.</author>
<author>Marsden, E.</author>
</authors>
Everytime when I've got a new XML document, I need to check a particular element (fullName) to update data dictionary file. The XML document looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<iris>
<creator>
<fullName>Wyatt, A.</fullName>
</creator>
...
</iris>
The key point for multiphase processing is to store the previous processing result into a variable and use that variable as the initial XML to process in the later phase. The example XSLT (in SAXON 9) is shown below:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
exclude-result-prefixes="xsl">
<xsl:strip-space elements="*"/>
<xsl:output method="xml" indent="yes"/>
<xsl:variable name="authorsDoc" select="document('authors.xml', /)"/>
<xsl:template match="/">
<!-- Phase 1 -->
<xsl:variable name="phase-1-output">
<authors>
<!-- If the newly entered author does not exist in current data dictionary,
then add it to DD -->
<xsl:for-each select="/iris/creator/fullName[.!='']">
<xsl:variable name="currentName" select=".[.=$authorsDoc//author]"/>
<xsl:if test="not($currentName)">
<author><xsl:value-of select="."/></author>
</xsl:if>
</xsl:for-each>
<!-- Copy all existing DD authors, only once -->
<xsl:for-each select="$authorsDoc/authors/author[.!='']">
<xsl:sort select="."/>
<author><xsl:value-of select="."/></author>
</xsl:for-each>
</authors>
</xsl:variable>
<!-- Phase 2 -->
<authors>
<xsl:for-each select="$phase-1-output/authors/author[.!='' and (not(.=preceding-sibling::author))]"> <!-- Remove duplicates -->
<xsl:sort select="."/>
<author><xsl:value-of select="."/></author>
</xsl:for-each>
</authors>
</xsl:template>
</xsl:stylesheet>
Showing posts with label saxon. Show all posts
Showing posts with label saxon. Show all posts
Monday, 20 February 2012
Tuesday, 31 January 2012
XSLT compatibility problem between XLAN and SAXON
When I'm implementing an XSLT to transform IRIS data dictionary items value (numbers, e.g. 02 08 etc) to descriptive texts for preview page, I found an incompatibility problem between XLAN and SAXON XSLT processor. It's mainly caused by the usage of tokenize funciton. The solution I found is:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:iris="http://iris-database.org/iris"
xmlns:str="http://exslt.org/strings"
exclude-result-prefixes="xsl str">
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:iris="http://iris-database.org/iris"
xmlns:str="http://exslt.org/strings"
exclude-result-prefixes="xsl str">
......
<xsl:choose>
<!-- For XLAN -->
<xsl:when test="function-available('str:tokenize')">
<xsl:for-each select="str:tokenize(.,' ')">
<xsl:variable name="currentType" select="."/>
<xsl:if test=".!='999'">
<iris:instrumentType><xsl:value-of select="$ddDoc/IRIS_Data_Dict/instrument/typeOfInstruments//type/@label[../@value=$currentType]"/></iris:instrumentType>
</xsl:if>
<xsl:if test=".='999'">
<iris:instrumentType><xsl:value-of select="$newType"/></iris:instrumentType>
</xsl:if>
</xsl:for-each>
</xsl:when>
<xsl:when test="function-available('str:tokenize')">
<xsl:for-each select="str:tokenize(.,' ')">
<xsl:variable name="currentType" select="."/>
<xsl:if test=".!='999'">
<iris:instrumentType><xsl:value-of select="$ddDoc/IRIS_Data_Dict/instrument/typeOfInstruments//type/@label[../@value=$currentType]"/></iris:instrumentType>
</xsl:if>
<xsl:if test=".='999'">
<iris:instrumentType><xsl:value-of select="$newType"/></iris:instrumentType>
</xsl:if>
</xsl:for-each>
</xsl:when>
<!-- For SAXON -->
<xsl:otherwise>
<xsl:for-each select="tokenize(.,' ')">
<xsl:variable name="currentType" select="."/>
<xsl:if test=".!='999'">
<iris:instrumentType><xsl:value-of select="$ddDoc/IRIS_Data_Dict/instrument/typeOfInstruments//type/@label[../@value=$currentType]"/></iris:instrumentType>
</xsl:if>
<xsl:if test=".='999'">
<iris:instrumentType><xsl:value-of select="$newType"/></iris:instrumentType>
</xsl:if>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
<xsl:otherwise>
<xsl:for-each select="tokenize(.,' ')">
<xsl:variable name="currentType" select="."/>
<xsl:if test=".!='999'">
<iris:instrumentType><xsl:value-of select="$ddDoc/IRIS_Data_Dict/instrument/typeOfInstruments//type/@label[../@value=$currentType]"/></iris:instrumentType>
</xsl:if>
<xsl:if test=".='999'">
<iris:instrumentType><xsl:value-of select="$newType"/></iris:instrumentType>
</xsl:if>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
Subscribe to:
Posts (Atom)