XSLT expression to check if HTML element exists - xslt

I am trying to test to see if a HTML element exists within XSLT but cannot get it to work. I am currently trying to assign a variable based on whether it can find it like this:
<xsl:variable name="TestParaText">
<xsl:choose>
<xsl:when test="contains(smf:body,index[#id='testSpan'])">
<xsl:value-of select="'Element found'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'Element Not Found'"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
Within my HTML I have this:
<span id="testSpan" style="display:none"></span>
I do not want the element to be visible so I have set a style attribute, but I am pretty sure its something to do with my poor xpath / XSLT syntax! Apologies, as I am not very knowledgeable on this topic but hopefully I should of provided enough information for someone to help me. Thanks

The contains function works on strings. If you would like to test if smf:body contains a node index[#id='testSpan']. You should have something like this:
<xsl:when test="body[descendant::index[#id='testSpan2']]">

If below is ur XML
INPUT XML :
<span id="testSpan" style="display:none"></span>
XSL:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="span">
<xsl:copy>
<xsl:choose>
<xsl:when test = "#id = 'testSpan'">
<TestParaText>
Exists
</TestParaText>
</xsl:when>
<xsl:otherwise>
<TestParaText>
Doesnt Exists
</TestParaText>
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
OUTPUT will be :
OUTPUT:
<?xml version="1.0" encoding="UTF-8"?>
<span>
<TestParaText>
Exists
</TestParaText>
</span>
Please share ur request xml and expected OUTPUT

Related

XSLT - Translate strings using key() lookup

I'm trying to solve a problem, where I have to translate strings using xslt.
I saw this: XSLT key() lookup
and this: XSLT Conditional Lookup Table
but I'm not able to get it to work. I've tried to come up with the minimal example below which shows the problems that I'm facing.
The "real" xsl is assembled from code snippets using a build process. This involves some constraints.
The inner structure of the translation lookup tables always is the same, since they are downloaded from a translation tool in flat xml format http://docs.translatehouse.org/projects/translate-toolkit/en/latest/formats/flatxml.html. I can only wrap them into distinct parent nodes which is what i tried using the "lu" namespace.
The translation tables for all languages have to be stored inside the xsl, because different generations of xsl with different translations may exist next to each other. So no "sidecar" files.
Until now I can't get the key to work. The output of xsltproc is the following:
Setup Key - Start
German
xsltApplyOneTemplate: key was not compiled
Setup Key - End
de # skipped #
de # failed #
Expected output:
Setup Key - Start
German
Setup Key - End
de # skipped # Übersprungen
de # failed # Fehlgeschlagen
The XML file just needs to contain a root element.
So obviously the way I try to define the key depending on the target language is wrong, but my xsl knowledge has reached its limit now. The language stays the same during the transformation, so the key for all translation lookups has to be set up only once at the beginning.
The xsl Transformation:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:lu="http://www.my.domain.de/lookup"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="vLanguageCode">
<!-- <xsl:value-of select="/root/#language"/> -->
<xsl:value-of select="'de'"/>
</xsl:variable>
<xsl:template match="/">
<xsl:call-template name="setupKey"/>
<xsl:call-template name="getLabel">
<xsl:with-param name="pKey" select="'skipped'"/>
</xsl:call-template>
<xsl:call-template name="getLabel">
<xsl:with-param name="pKey" select="'failed'"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="setupKey">
<xsl:message>Setup Key - Start</xsl:message>
<xsl:choose>
<xsl:when test="$vLanguageCode='DE' or $vLanguageCode='de'">
<xsl:message>German</xsl:message>
<xsl:key name="kLanguageDict" match="/lu:de/root/str" use="#key"/>
</xsl:when>
<xsl:otherwise>
<xsl:message>English (default)</xsl:message>
<xsl:key name="kLanguageDict" match="/lu:en/root/str" use="#key"/>
</xsl:otherwise>
</xsl:choose>
<xsl:message>Setup Key - End</xsl:message>
</xsl:template>
<xsl:template name="getLabel">
<xsl:param name="pKey"/>
<xsl:variable name="vResult">
<xsl:value-of select="key('kLanguageDict', $pKey)/#str"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="$vResult!=''">
<xsl:value-of select="$vResult"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$pKey"/>
</xsl:otherwise>
</xsl:choose>
<xsl:message>
<xsl:value-of select="concat($vLanguageCode, ' # ', $pKey, ' # ', $vResult)"/>
</xsl:message>
</xsl:template>
<lu:de>
<root>
<str key="skipped">Übersprungen</str>
<str key="failed">Fehlgeschlagen</str>
</root>
</lu:de>
<lu:en>
<root>
<str key="skipped">Skipped</str>
<str key="failed">Failed</str>
</root>
</lu:en>
</xsl:stylesheet>
Additions in response to the answer from #michael.hor257k:
Thank you. I didn't know that. So this means that I can't selectively define a key depending on language?
The translation system originally has one key at the top level and a translation table with interleaved entries for each language. It uses a double index (language+id) to look up the values.
I am trying to find a solution where I can embed the xml files returned by the translation management system (weblate) directly into the xsl without having to modify them. Unfortunately it looks like I'm limited in what I can get back (only default nodes and attributes).
This is the core of the original working translation lookup code:
<xsl:variable name="vLanguageDict" select="document('')/*/lu:strings"/>
<xsl:key name="kLanguageDict" match="lu:string" use="concat(#lang,#id)"/>
<xsl:template name="getLabel">
<xsl:param name="pKey"/>
<xsl:variable name="vResult">
<xsl:for-each select="$vLanguageDict">
<xsl:value-of select="key('kLanguageDict', concat($vLanguageCode,$pKey))/#value" />
</xsl:for-each>
</xsl:variable>
<xsl:choose>
<xsl:when test="$vResult!=''">
<xsl:value-of select="$vResult"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$pKey"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<lu:strings>
<lu:string lang="DE" id="skipped" value="Übersprungen"/>
<lu:string lang="EN" id="skipped" value="skipped"/>
<lu:string lang="DE" id="failed" value="Fehlgeschlagen"/>
<lu:string lang="EN" id="failed" value="failed"/>
</lu:strings>
There are two mistakes in your XSLT stylesheet that immediately jump out:
The xsl:key element is allowed only at the top level, as a child
of the xsl:stylesheet element.
In XSLT 1.0, keys operate only on the current document. If you want to lookup from the stylesheet itself, you must change the context to the stylesheet document before calling the key() function. Here are two examples: https://stackoverflow.com/a/32440143/3016153
https://stackoverflow.com/a/30188334/3016153
I am afraid that's about all that can be said without a reproducible example.
--- added ---
So this means that I can't selectively define a key depending on language?
You cannot define a key conditionally - but you can define more than one key and select the one to use based on the specified language. Here's a simplified example:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:dict="http://example.com/dict">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:key name="de" match="dict:de/entry" use="#key" />
<xsl:key name="en" match="dict:en/entry" use="#key" />
<xsl:param name="input">skipped</xsl:param>
<xsl:param name="lang">de</xsl:param>
<xsl:template match="/">
<xsl:value-of select="$lang"/>
<xsl:text> # </xsl:text>
<xsl:value-of select="$input"/>
<xsl:text> = </xsl:text>
<!-- switch context to stylesheet in order to use key -->
<xsl:for-each select="document('')">
<xsl:value-of select="key($lang, $input)"/>
</xsl:for-each>
</xsl:template>
<dict:de>
<entry key="skipped">Übersprungen</entry>
<entry key="failed">Fehlgeschlagen</entry>
</dict:de>
<dict:en>
<entry key="skipped">Skipped</entry>
<entry key="failed">Failed</entry>
</dict:en>
</xsl:stylesheet>
Applied to any XML input, this will return:
Result
de : skipped = Übersprungen

Starts with not working in while check in Xsl

I have tried different ways but not able to figure out the mistake.I have to do 2 checks to set the value of an attribute.The below example is a simple version of it.
Input XML
`
<Detail Type="3242432" LastDate="2016-04-22T11:02:43+01:00"
NodName="10001"
UpdateValueReason="Apple: 123 56"
Date="2016-04-22T11:02:43+01:00">
<Sub EventID="2">
</Detail>
`
XSL
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/Detail/Sub">
<Status>
<xsl:attribute name="StatusType">
<xsl:choose>
<xsl:when test="../starts-with(#UpdateValueReason, 'Apple') and #EventID='2'">
<xsl:value-of select="'23'" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'1234'" />
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</Status>
</xsl:template>
</xsl:stylesheet>
Here I am checking if an attribute starts with certain set of char I am stamping another attribute, but its throwing error
Error while running on cooktop
Error:
ERROR: Description: NodeTest expected here.
../-->starts-with<--(#UpdateValueReason, 'Apple') and #EventID='2'
Your current syntax would work with XSLT 2.0, but not XSLT 1.0.
Try this instead for XSLT 1.0:
<xsl:when test="starts-with(../#UpdateValueReason, 'Apple') and #EventID='2'">

XSL test for a value

I want to do a test in XSLT 1.0 to see if a variable contains a web link. I thought I would be able to do some sort of regex but it doesn't seem that 1.0 can do that. Right now the code assumes that the attribute doesn't have http://myserver.com. I'd like to be able to see if the variable contains http://someotherserver.com/.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
.........
<xsl:for-each select="links/link">
<li>
<xsl:text a href="http://myserver.com/</xsl:text> <xsl:value-of select="#link" disable-output-escaping="yes"/>
</li>
</xsl:for-each>
I'd like to be able to see if the variable contains
http://someotherserver.com/.
There is no regex in XSLT 1.0. And there is no variable in your code, so it's hard to be specific - but in general, you can use the contains() function to determine if a string contains another string.
For example:
<xsl:for-each select="links/link">
<xsl:choose>
<xsl:when test="contains(#link, 'http://someotherserver.com/')">
<!-- do something here -->
</xsl:when>
<xsl:otherwise>
<!-- do something else -->
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>

XSLT Node availability check

I want to check a variable have any node or any attribute.
XSL:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="/">
<xsl:variable name="testvar">
<test><name first="Isaac" last="Sivakumar" middle="G"></name></test>
</xsl:variable>
<xsl:choose>
<xsl:when test="normalize-space($testvar)">
<xsl:value-of select="$testvar"></xsl:value-of>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'NO XML DATA AVAILABLE'"></xsl:value-of>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
When I try to run the above code I am getting "NO XML DATA AVIALABLE." I need to check weather a variable has any node / any attributes irrespective of it has data or not.
Can you please help me to fix this.
With XSLT 1.0 your variable has a value of type "result tree fragment", you need to use an extension function to convert it to a node set first to be able to address nodes e.g.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common" version="1.0">
<xsl:template match="/">
<xsl:variable name="testvar">
<test><name first="Isaac" last="Sivakumar" middle="G"></name></test>
</xsl:variable>
<xsl:choose>
<xsl:when test="exsl:node-set($testvar)/node()">
<xsl:copy-of select="$testvar"></xsl:value-of>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'NO XML DATA AVAILABLE'"></xsl:value-of>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Using normalize-space or value-of does not make much sense given that your XML in the result tree fragment has all data in attributes and no text nodes with data.
And the test test="exsl:node-set($testvar)/node()" is just an example, it could of course use e.g. test="exsl:node-set($testvar)//name" to test for a specific element like a name element.
Given XSLT 1.0 but EXSLT common support it might be better to check with http://www.exslt.org/exsl/functions/object-type/index.html e.g.
<xsl:choose>
<xsl:when test="exsl:object-type($testvar) = 'string' and $testvar = ''">
<xsl:value-of select="'NO XML DATA AVAILABLE'"/>
</xsl:when>
<xsl:when test="exsl:object-type($testvar) = 'node-set'">
<xsl:copy-of select="$testvar"/>
</xsl:when>
</xsl:choose>
Given XSLT 2.0 I would simply check e.g if ($testvar instance of xs:string and $testvar = '') then 'NO XML DATA AVAILABLE' else $testvar.

How to declare variable as a link in XSLT

Hi is there away on how to declare a link(ie:http://www.google.com) as a variable and then using the variable for an else if?Something like this?
<xsl:element name="a">
<xsl:attribute name="href">http://www.google.com</xsl:attribute>// first get the link
<xsl:choose>
<xsl:when test="http://www.google.com">
Do something 1
</xsl:when>
<xsl:otherwise>
Do something 2
</xsl:choose>
</xsl:element>
Is this possible?What should i be looking at?
is there away on how to declare a
link(ie:http://www.google.com) as a
variable and then using the variable
for an else if?
Use this code as a working example -- of course you need to learn at least the basics of XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="vLink" select="'http://www.google.com'"/>
<xsl:template match="/">
<xsl:choose>
<xsl:when test="$vLink = 'http://www.google.com'">
It is the Google link...
</xsl:when>
<xsl:otherwise>
It is not (exactly) the Google link...
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied on any XML document (not used), the wanted result is produced:
It is the Google link...
One can also use a global <xsl:param>. This can be set externally by the invoker of the transformation.
Match against the content straight forward, and declare the URL as a variable.
If you need it more globally try this:
...
<xsl:apply-templates select="a" />
...
<xsl:template match="a">
Just a link
</xsl:template>
<xsl:template match="a[starts-with(#href, 'http://google.com/') or starts-with(#href, 'http://www.google.com/')]">
Link to google.com
</xsl:template>
It's possible to some extent, but there is no if-else construct in XSL. Here's a version I tested that you might be able to adapt to your needs. The input I used was:
<?xml-stylesheet type="text/xsl" href="test.xsl"?>
<xml>
<LinkValue>http://www.google.com/</LinkValue>
</xml>
The XSL that showing "Do something 1" if LinkValue was the string above or "Do something 2" if I modified it was:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="LinkValue" select="//LinkValue"/>
<xsl:element name="a">
<xsl:attribute name="href"><xsl:value-of select="$LinkValue"/></xsl:attribute>
<xsl:if test="$LinkValue = 'http://www.google.com/'">
Do something 1
</xsl:if>
<xsl:if test="$LinkValue != 'http://www.google.com/'">
Do something 2
</xsl:if>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Hopefully you can use these samples to figure out exactly what you need to implement for your scenario.