Getting a template to apply a class to a span based on conditional results of passed in parameters - xslt-1.0

This is only a test script and I can supply a two test XML data blocks if required.
The script:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msa="http://www.publictalksoftware.co.uk/msa">
<xsl:output method="html" indent="yes" version="4.01"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
doctype-public="//W3C//DTD XHTML 1.0 Transitional//EN"/>
<xsl:variable name="PubDB" select="document('MSA_PublisherDatabase.XML')"/>
<xsl:template match="/">
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Test</title>
</head>
<body>
<xsl:for-each select="MeetingWorkBook/Meeting">
<xsl:call-template name="IsAvailableMidweek">
<xsl:with-param name="strName" select="Chairman"/>
</xsl:call-template>
</xsl:for-each>
</body>
</html>
</xsl:template>
<xsl:template name="IsAvailableMidweek">
<xsl:param name="strName"/>
<xsl:variable name="thePublisher" select="$PubDB/msa:PublisherDatabase/msa:Publishers/msa:Publisher[msa:Name=$strName]"/>
<xsl:if test="$thePublisher">
<xsl:choose>
<xsl:when test="$thePublisher/msa:Availability/#Midweek='false'">
<p>Not available #Midweek</p>
</xsl:when>
<xsl:otherwise>
<xsl:variable name ="datMonth" select="format-number(MeetingDate/#Month,'00')"/>
<xsl:variable name ="datDay" select="format-number(MeetingDate/#Day,'00')"/>
<xsl:variable name="datMeeting" select="concat(MeetingDate/#Year, '-', $datMonth, '-', $datDay)"/>
<xsl:choose>
<xsl:when test="$thePublisher/msa:Availability/msa:DatesNotAvailable[msa:Date=$datMeeting]">
<p>
<xsl:text>Not available for date </xsl:text>
<xsl:value-of select="$datMeeting"/>
</p>
</xsl:when>
<xsl:otherwise>
<p>Available</p>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
I have been working on the IsAvailableMidweek template and in principle it works. The content it displays was for debugging purposes.
The challenge I have is that I want to display (this this specific case) the Chairman in a span as text. If he is determined as "Not Available" then I want to apply a class of NotAvailable to the span object.
I know how to display the value in a span. That is straightforward. But how do I adjust the template IsAvailableMidweek I have written so that it can apply this class if it determines the person is not available?
I hope this makes sense. I don't think I can use functions in with XSLT-1.

I don't know if this is the best way, but it appears to do what I am looking for:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msa="http://www.publictalksoftware.co.uk/msa">
<xsl:output method="html" indent="yes" version="4.01"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
doctype-public="//W3C//DTD XHTML 1.0 Transitional//EN"/>
<xsl:variable name="PubDB" select="document('MSA_PublisherDatabase.XML')"/>
<xsl:template match="/">
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Test</title>
</head>
<body>
<xsl:for-each select="MeetingWorkBook/Meeting">
<p>
<xsl:call-template name="SetClassName">
<xsl:with-param name="strName" select="Chairman"/>
</xsl:call-template>
<xsl:value-of select="Chairman"/>
</p>
</xsl:for-each>
</body>
</html>
</xsl:template>
<xsl:template name="SetClassName">
<xsl:param name="strName"/>
<xsl:variable name="thePublisher" select="$PubDB/msa:PublisherDatabase/msa:Publishers/msa:Publisher[msa:Name=$strName]"/>
<xsl:if test="$thePublisher">
<xsl:choose>
<xsl:when test="$thePublisher/msa:Availability/#Midweek='false'">
<xsl:attribute name="class">NotAvailable</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:variable name ="datMonth" select="format-number(MeetingDate/#Month,'00')"/>
<xsl:variable name ="datDay" select="format-number(MeetingDate/#Day,'00')"/>
<xsl:variable name="datMeeting" select="concat(MeetingDate/#Year, '-', $datMonth, '-', $datDay)"/>
<xsl:choose>
<xsl:when test="$thePublisher/msa:Availability/msa:DatesNotAvailable[msa:Date=$datMeeting]">
<xsl:attribute name="class">NotAvailable</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<!-- Available — Do Further Tests -->
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

Related

I want to split the string stored in a variable and store the obtained values in variable using xslt

<xsl:variable name="AAM" select="//AAM"/>
AAM will have string value_1,value_2,value_3,value_4
I then want to split this and store in 4 variables :
seg1,
seg2,
seg3,
seg4
Assuming the below as your input:
<?xml version="1.0" encoding="UTF-8"?>
<body>
<AAM>value_1,value_2,value_3,value_4</AAM>
</body>
An XSLT 2.0 solution to split a comma separated string can be:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:variable name="AAM" select="//AAM" />
<xsl:template match="body">
<body>
<xsl:variable name="separator" select="','" />
<xsl:for-each select="tokenize($AAM,$separator)">
<xsl:element name="seg{position()}">
<xsl:value-of select="normalize-space(.)" />
</xsl:element>
</xsl:for-each>
</body>
</xsl:template>
http://xsltransform.net/6qaFCET/1
Edit: (Based on commented)
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:variable name="AAM" select="//AAM" />
<xsl:template match="body">
<body>
<xsl:variable name="separator" select="','" />
<xsl:for-each select="tokenize($AAM,$separator)">
<xsl:choose>
<xsl:when test="position() = 1">
<xsl:variable name="seg1">
<xsl:value-of select="normalize-space(.)" />
</xsl:variable>
<xsl:copy-of select="$seg1" />
<xsl:text>
</xsl:text>
</xsl:when>
<xsl:when test="position() = 2">
<xsl:variable name="seg2">
<xsl:value-of select="normalize-space(.)" />
</xsl:variable>
<xsl:copy-of select="$seg2" />
<xsl:text>
</xsl:text>
</xsl:when>
<xsl:when test="position() = 3">
<xsl:variable name="seg3">
<xsl:value-of select="normalize-space(.)" />
</xsl:variable>
<xsl:copy-of select="$seg3" />
<xsl:text>
</xsl:text>
</xsl:when>
<xsl:when test="position() = 4">
<xsl:variable name="seg4">
<xsl:value-of select="normalize-space(.)" />
</xsl:variable>
<xsl:copy-of select="$seg4" />
<xsl:text>
</xsl:text>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</body>
</xsl:template>
http://xsltransform.net/6qaFCET/2
Note: following lines can be avoided. It has been added to populate value of variables.
<xsl:copy-of select="$seg2" />
<xsl:text>
</xsl:text>
Assuming you have <AAM>value_1,value_2,value_3,value_4</AAM> and <xsl:variable name="AAM" select="//AAM"/> you can of course use e.g. <xsl:variable name="value-sequence" select="tokenize($AAM, ',')"/> and if then needed access e.g. $value-sequence[1], $value-sequence[2] and so on, thus if you know there are only four values you can declare <xsl:variable name="seq1" select="$value-sequence[1]"/>, <xsl:variable name="seq2" select="$value-sequence[2]"/> and so on. The tokenize function is part of XPath 2 and later so works with XSLT 2 or 3 processors like Saxon 9 or AltovaXML or XmlPrime.
Answering late.
Maybe this is not an exact solution. But this may help you.
This is how I'm able to split a string from an XML node into two variables using XSLT 1.0
<xsl:when test="NodeName">
<xsl:variable name="var" select="NodeName"/>
<xsl:variable name="var1" select="substring-before($var, '=')"/>
<xsl:variable name="var2" select="substring-after($var, '=')"/>
<xsl:value-of select="$var1"/>-
<xsl:value-of select="$var2"/>
</xsl:when>
For Further reference Click Here

Reading values of XML tag in variables inside XSLT

I could not find a similar question anywhere, so thats why posting this new question.
I have an XML that I want to read and convert into SQL using XSLT. The trick part is that the XML elements(i.e. the names) are not known and the XSD for the XML is generated on the fly.
But what is known is certain attributes of the elements.
The XML looks like this :
<?xml version="1.0" encoding="UTF-8"?>
<et:ItemRecordList xmlns:et="urn:org:easetech:easytest:schema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:org:easetech:easytest:schema ItemRecord.xsd ">
<ItemRecord recordId="idvalue0" tableName="item_record">
<itemId columnName="item_id" idColumn="true" length="36" nullable="false">itemId</itemId>
<databaseInstitution columnName="database_institution" length="255" nullable="false">0</databaseInstitution>
<lastModifiedDate columnName="last_modified_date" length="255" nullable="false">2001-12-31T12:00:00</lastModifiedDate>
</ItemRecord>
</et:ItemRecordList>
I want to use this XML and convert it into an INSERT SQL statement using XXSLT.
I created an XSLT like this :
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8" />
<xsl:template match="/">
<xsl:for-each select="/*/*">
INSERT INTO
<xsl:value-of select="#tableName" />
(
<xsl:for-each select="/*/*/*">
<xsl:variable name="columnName"><xsl:value-of select="#columnName"/></xsl:variable>
<xsl:choose>
<xsl:when test="#columnName">
<xsl:value-of select="$columnName"/>
<xsl:if test="position()!=last()">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:when>
</xsl:choose>
</xsl:for-each>
)
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
which gives me the output like this :
INSERT INTO item_record (item_id, database_institution, last_modified_date)
But I don't know how to create the value part of the query. The value is the value we get using
<xsl:value-of select="." />
I tried concatenating the values, but unfortunately concat didnt work for me. I also played around with xsl:variable but couldnt make it work. If someone could help me with the XSLT that I can use to create to output like below that would be really appreciated.
INSERT INTO item_record (item_id, database_institution, last_modified_date) values (itemId,0,2001-12-31T12:00:00)
How about:
<xsl:template match="/">
<xsl:for-each select="/*/*">
<xsl:text>INSERT INTO </xsl:text>
<xsl:value-of select="#tableName" />
<xsl:text> (</xsl:text>
<xsl:for-each select="*[#columnName]">
<xsl:value-of select="#columnName"/>
<xsl:if test="position()!=last()">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:text>) values (</xsl:text>
<xsl:for-each select="*[#columnName]">
<xsl:value-of select="."/>
<xsl:if test="position()!=last()">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
The next XSLT will generate the query as wanted
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:variable name="newline" select="'
'" />
<xsl:template match="/">
<xsl:apply-templates select="*/*/#tableName" />
</xsl:template>
<xsl:template match="#tableName">
<xsl:value-of select="concat('INSERT INTO ', ., ' (')" />
<xsl:apply-templates select="parent::*/*/#columnName" />
<xsl:value-of select="') VALUES ('" />
<xsl:apply-templates select="parent::*/*" mode="values" />
<xsl:value-of select="concat(')', $newline)" />
</xsl:template>
<xsl:template match="#columnName">
<xsl:choose>
<xsl:when test="position() = last()">
<xsl:value-of select="." />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(., ', ')" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="*" mode="values">
<xsl:choose>
<xsl:when test="position() = last()">
<xsl:value-of select="." />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(., ', ')" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

XSL match multiple variables with XML

I'm trying to match xsl variables i.e. key1, key2 with xml node strings.
Problem: the xsl variables can vary like key1, key2, key3, key4, until key.length...
Question: How can I modify my xsl so when the key[i] is used, then ti will display all the xml node matches.
Here's my XML:
<?xml version="1.0" encoding="UTF-8"?>
<document>
<metadata>
<field>marketing business</field>
<field>PageTitle1 One</field>
<field>marketing business link</field>
<field>planning development</field>
<field>PageTitle2 Two</field>
<field>planning development link</field>
<field>learning development</field>
<field>PageTitle3 Threee</field>
<field>learning development link</field>
</metadata>
</document>
Here's my XSL:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="key1">marketing</xsl:variable>
<xsl:variable name="key2">business</xsl:variable>
<xsl:for-each select="document/metadata/field">
<xsl:choose>
<xsl:when test="contains(.,$key1) and contains(.,$key2)">
match <xsl:value-of select="." /><br/>
</xsl:when>
<xsl:when test="contains(.,$key2)">
match <xsl:value-of select="." /><br/>
</xsl:when>
<!--... add other options here-->
<xsl:otherwise></xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
Result:
match marketing business
match marketing business link
Any help? or is there a way to put this in an array-like variable or any different approach?...
Consider putting your "keys" in a separate XML document, call it "keys.xml"
<keys>
<key>marketing</key>
<key>business</key>
</keys>
Then, you can create a single variable in your XSLT to reference this document
<xsl:variable name="keys" select="document('keys.xml')/keys" />
With this variable you can then, for example, check if your field element matches all the keys like so:
<xsl:variable name="matches" select="count($keys/key[contains(current(), .)])" />
<xsl:choose>
<xsl:when test="$matches = count($keys/key)">
Try this XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:variable name="keys" select="document('keys.xml')/keys" />
<xsl:variable name="totalkeys" select="count($keys/key)" />
<xsl:template match="/">
<xsl:for-each select="document/metadata/field">
<xsl:variable name="matches" select="count($keys/key[contains(current(), .)])" />
<xsl:choose>
<xsl:when test="$matches = $totalkeys">
matches all <xsl:value-of select="." /><br/>
</xsl:when>
<xsl:when test="$matches = 1">
matches one <xsl:value-of select="." /><br/>
</xsl:when>
<xsl:when test="$matches > 0">
matches some <xsl:value-of select="." /><br/>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Looking to insert div into html body with xsl 1.0

Pretty simple: What I'm looking for a simple XSL to change
<body>
...
</body>
To
<body>
...
<div>...</div>
</body>
<xsl:template match="body">
<xsl:apply-templates />
<div>...</div>
</xsl:template>
<xsl:template match="*">
<xsl:variable name="curTagName" select="name()"/>
<xsl:element name="{$curTagName}">
<!-- Walk through the attributes -->
<xsl:apply-templates select="#*">
<xsl:sort select="name()"/>
</xsl:apply-templates>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="#*">
<xsl:variable name="curAttName" select="name()"/>
<xsl:attribute name="{$curAttName}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>

Remove all single characters from string using xslt1.0

<title>
<article_title>Land a b c d Band</article_title>
</title>
using the following function
replace(article_title, '(^[^ ]+)(.+\s+)([^ ]+)$', '$1 $3')
this string in is transformed to Land Band which is exactly what i want.
but the problem is i need this solution in xslt 1.0 since the java app that i am working with can only handle xslt 1.0 parsing.
This XSLT 1.0 transformation (there is a nasty SO bug and the code isn't indented -- I apologize for this visual mess...):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()" name="removeSingles">
<xsl:param name="pText" select="."/>
<xsl:variable name="vText" select="normalize-space($pText)"/>
<xsl:if test="string-length($vText)">
<xsl:variable name="vLeftChars" select=
"substring-before(concat($vText, ' '), ' ')"/>
<xsl:if test="string-length($vLeftChars) >1">
<xsl:value-of select="$vLeftChars"/>
<xsl:if test=
"not(string-length($vLeftChars)
>=
string-length($vText)
)
">
<xsl:text> </xsl:text>
</xsl:if>
</xsl:if>
<xsl:call-template name="removeSingles">
<xsl:with-param name="pText" select=
"substring-after($vText, ' ')"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<title>
<article_title>Land a b c d Band</article_title>
</title>
produces the wanted, correct result:
<title>
<article_title>Land Band</article_title>
</title>