Convert output of xsl to a url upon conditions - html

I'm very much a novice at the moment, however I have used xsl to format an xml feed to out put into html for my site. However, I would like to go a step further by also converting some of the output text to an html link.
Are there any tutorials available that could help?
To give a bit better context, the output is a football league table, that I would like to make the teams names automatically link to a url. So if name = 'Portsmouth' then I would want Portsmouth to become a link I would determine. How do I format the table below to do this for all the potentially different team names?
<xsl:for-each select="team">
<tr>
<td><xsl:value-of select="position"/></td>
<td><xsl:value-of select="name"/></td>
<td><xsl:value-of select="played"/></td>
<td><xsl:value-of select="won"/></td>
<td><xsl:value-of select="drawn"/></td>
<td><xsl:value-of select="lost"/></td>
<td><xsl:value-of select="for"/></td>
<td><xsl:value-of select="against"/></td>
<td><xsl:value-of select="goalDifference"/></td>
<td><xsl:value-of select="points"/></td>
</tr>
`

If you want to conditionally output a tags you can do the following.
<xsl:template match="/">
<xsl:apply-templates select="//team"/>
</xsl:template>
<xsl:template match="team">
<td>
<xsl:value-of select="position"/>
</td>
<td>
<xsl:choose>
<xsl:when test="name='Portsmouth'">
<a>
<xsl:attribute name="href">
<xsl:value-of select="concat('someurl.com?name=',name)"/>
</xsl:attribute>
</a>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="name"/>
</xsl:otherwise>
</xsl:choose>
</td>
<td>
<xsl:value-of select="played"/>
</td>
<td>
<xsl:value-of select="won"/>
</td>
<td>
<xsl:value-of select="drawn"/>
</td>
<td>
<xsl:value-of select="lost"/>
</td>
<td>
<xsl:value-of select="for"/>
</td>
<td>
<xsl:value-of select="against"/>
</td>
<td>
<xsl:value-of select="goalDifference"/>
</td>
<td>
<xsl:value-of select="points"/>
</td>
</xsl:template>
Use apply-templates instead of a foreach loop.
If one of the teams is Portsmouth, the output would be
<td><a href="someurl.com?name=Portsmouth"/></td>
If you want each team to have a url then simply remove the choose statement and leave
<td>
<a>
<xsl:attribute name="href">
<xsl:value-of select="concat('someurl.com?name=',name)"/>
</xsl:attribute>
</a>
</td>

Related

How to add conditions to xsl for-each statements

I'm trying to filter out any amount below $1,000,000. Here is the code:
<xsl:for-each select="row">
<tr>
<xsl:for-each select="cell">
<xsl:if test="position()=5">
<td width="140" style="vertical-align: top; padding: 3px;" valign="top">
<xsl:choose>
<xsl:when test="#href">
<a href="">
<xsl:attribute name="href">
<xsl:value-of select="#href" />
</xsl:attribute>
<xsl:value-of select="." />
</a>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="." />
</xsl:otherwise>
</xsl:choose>
</td>
</xsl:if>
<xsl:if test="position()=8">
<td class="categorydetail-last-column" style="text-align: right; vertical-align: top; padding: 3px;" align="right" valign="top">
<xsl:value-of select="." /><!-- THIS OUTPUTS NUMBERS. WANT TO FILTER NUMBERS BELOW 1000000 -->
</td>
</xsl:if>
</xsl:for-each>
</tr>
</xsl:for-each>
It outputs dollar amount but it needs to output if it's bigger than one million. I tried creating variables and wrapping the whole code in IF statement but it didn't work. What am I doing wrong? Do I have to add condition to the ROW?
As I understood, you want to process only rows in which cell No 8
contains value less than a million.
So use a template with the match condition specifying just this
filtering criterion:
<xsl:template match="row[cell[8] < 1000000]">
...
</xsl:template>
If your XSLT script contains also an identity template, you must
somehow "block" other rows from proessing. You can do it with a
"more general", empty template, for all rows:
<xsl:template match="row"/>
Actually, it would be applied to all "other" rows (to which the former
template does not apply).
Another solution (more close to the script you posted):
Change the "external" loop to:
<xsl:for-each select="row[cell[8] < 1000000]">

Dynamic HTML Table with XSLT

I need to loop over a group of values and print them into a two-column table.
I thought about following solution (must be xslt1)
<table class="main">
<xsl:for-each select="Attribute/Gruppe">
<xsl:if test="current()/#ID=20064490">
<xsl:variable name="open_row"><![CDATA[<tr><td style="width:50%;">
<xsl:value-of select="current()/#name" /></td>]]></xsl:variable>
<xsl:variable name="closing_row"><![CDATA[<td style="width:50%;">
<xsl:value-of select="current()/#name" /></td></tr>]]></xsl:variable>
<xsl:variable name="table">
<xsl:for-each select="*">
<xsl:choose>
<xsl:when test="(position() mod 2) = 1">
<xsl:value-of select="$open_row"
disable-output-escaping="yes" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$closing_row"
disable-output-escaping="yes" />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:variable>
<xsl:value-of select="$table"
disable-output-escaping="yes" />
</xsl:if>
</xsl:for-each>
</table>
I modified the code now I am using position() to find out if an closing <tr> or an opening </tr> is required.
The whole problem might be summarized to that you can not write single tags in XSLT. And that disable-output-escaping is not working.
Resulting HTML should be https://jsfiddle.net/dwetctm6/
For all the Nodes in the group. The order of the nodes in the table does not matter.
Furthermore assume following XML:
<bgroup>
<NODE1>text</NODE1>
<NODE2>text</NODE2>
<NODE n-1>text</NODE n-1>
<NODE n>text</NODE n>
</bgroup>
Dividing nodes into a two-column table is pretty trivial - especially if the order (across-first or down-first) does not matter.
Consider the following stylesheet:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:template match="/bgroup">
<table border="1">
<xsl:for-each select="*[position() mod 2 = 1]">
<tr>
<td><xsl:value-of select="."/></td>
<td><xsl:value-of select="following-sibling::*[1]"/></td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
Applied to the following well-formed inpout:
XML
<bgroup>
<NODE1>A</NODE1>
<NODE2>B</NODE2>
<NODE3>C</NODE3>
<NODE4>D</NODE4>
<NODE5>E</NODE5>
</bgroup>
the result will be:
<table border="1">
<tr>
<td>A</td>
<td>B</td>
</tr>
<tr>
<td>C</td>
<td>D</td>
</tr>
<tr>
<td>E</td>
<td/>
</tr>
</table>
rendered as:
Well, a few remarks must be made first of all:
You must learn how XSLT works: It is a language for templating that, being based on XML, must be composed in an ordered way: Every node open must be closed within the same scope. michael.hor257k is right: You shall not open a node within an scope and close it in another different one.
Also, there must be said that your input XML does not seem to be properly structured: It should be a repetition of nodes with same names and types. If all the NODE-n nodes are functionally or semantically equal, they should have the same name, no problem: You can have several nodes with the same name.
And now, the solution: Asuming your XML is as you have posted it, and since there can't be a templating definition based upon named nodes with different names, I have matched all the child nodes of the bgroup root node. So, the XSL can be as easy as this:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/bgroup">
<html>
<body>
<table>
<xsl:apply-templates select="*[position() mod 2 =1]"/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="*">
<tr>
<td><xsl:value-of select="."/></td>
<td><xsl:value-of select="following-sibling::*[1]"/></td>
</tr>
</xsl:template>
</xsl:stylesheet>
It's important that you realise how, thanks to the ordered structure of the XSL language, you can see how the output will be with just a glimpse of the XSL template.

XSLT: Transforming HTML attributes into inline CSS

I have invalid HTML that I am trying to transform into valid HTML using an XSLT transformation. For example, I want to turn some attributes into inline CSS. Consider the following:
<table border="1" id="t01" width="100%">
.
.
.
</table>
The border and width attributes on the table element are obsolete. So I want to use inline CSS instead, like this:
<table style="border:1;width:100%;" id="t01">
.
.
.
</table>
How can I do this with XSLT?
You could certainly make this prettier, more generic, etc., but my first pass would be something like:
<xsl:template match="table">
<table>
<xsl:attribute name="style">
<xsl:if test="#border">
<xsl:value-of select="concat('border:', #border, '; ')"/>
</xsl:if>
<xsl:if test="#width">
<xsl:value-of select="concat('width:', #width, '; ')"/>
</xsl:if>
</xsl:attribute>
<xsl:copy-of select="#id"/>
<!-- either this or apply-templates -->
<xsl:copy-of select="*"/>
</table>
</xsl:template>

XLST query to remove unwanted element in returned XML

I have an amended XSLT query thats returning everything I want but with an additional element i do not want there. how can i amend it so it get rid of the <identifier type="nt">80df0b42de8f31ac4cb7a30d325ff0c1</identifier> line. the xml is:
<?xml version="1.0" encoding="UTF-8"?>
<CMDBTopology>
<Objects>
<CMDBSet>
<name>80df0b42de8f31ac4cb7a30d325ff0c1</name>
<CMDBObject>
<identifier type="nt">80df0b42de8f31ac4cb7a30d325ff0c1</identifier>
<Properties>
<root_class type="STRING">nt</root_class>
<host_servertype type="STRING"></host_servertype>
<host_osrelease type="STRING"></host_osrelease>
<display_label type="STRING">pharsm-s3004</display_label>
<host_osinstalltype type="STRING"></host_osinstalltype>
</Properties>
</CMDBObject>
and the xlst query that i have at the moment is `
<html>
<head>
<title> title </title>
</head>
<body>
<xsl:apply-templates />
</body>
</html>
<table width="1" border="1" >
<tr>
<td> <xsl:value-of select="display_label" /> </td>
<td> <xsl:value-of select="root_class" /> </td>
<td> <xsl:value-of select="resolver_group" /> </td>
<td> <xsl:value-of select="supported_by" /> </td>
<td> <xsl:value-of select="environment" /> </td>
<td> <xsl:value-of select="site_code" /> </td>
<td> <xsl:value-of select="sla_classification" /> </td>
<td> <xsl:value-of select="datacenter" /> </td>
</tr>
</table>
`
It's hard to give a precise answer, not knowing exactly what you want your output to look like, but your main problem is that you have a template matching CMDBRelation in your XSLT, like so...
<xsl:template match="CMDBRelation" >
But there is no such CMDBRelation element in your XML! This means this template will never get called. This means, when you do <xsl:apply-templates /> in your first template, then XSLT's "built-in templates" are being used. These effectively iterate over all nodes in the XML, outputting text nodes where they find them, which is why you get all the text printing out and no table formatting.
I suspect your template actually needs to match CMDBSet
<xsl:template match="CMDBRelation" >
You also seem to be referring to To and From elements in your xsl:for-each statements, and as before, such elements don't exist in your XML.
<xsl:for-each select="To/CMDBObject/Properties">
It is possible you need to combine the two statements into one, like this
<xsl:for-each select="CMDBObject/Properties">
Here is some amended XSLT to start you off, that does produce a table and doesn't output any identifier element.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<head>
<title> title </title>
</head>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="CMDBSet">
<table width="1" border="1">
<xsl:for-each select="CMDBObject/Properties">
<tr>
<td><xsl:value-of select="display_label"/></td>
<td><xsl:value-of select="root_class"/></td>
<td><xsl:value-of select="host_servertype"/></td>
<td><xsl:value-of select="host_osrelease"/></td>
<td><xsl:value-of select="host_osinstall"/></td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>

How to compare XML element with XSL variable

I am using xslt to transform an xml document to html for use in an email. I need to compare xml elements with another xml element value so that I know what format to give the value. Basically I have an xml structure as such:
<main>
<comparer>1</comparer>
<items>
<item>
<name>blarg</name>
<values>
<value>1</value>
<value>2</value>
</values>
</items>
</main>
The item information is being used to build a table:
<table>
<tr>
<td>blarg</td>
<td>1</td>
<td>2</td>
</tr>
</table>
What I need to be able to do is use xsl to compare the item values with the 'comparer' node value and if they are equal then bold the cell in the table otherwise the cell value i snot bolded. I need to accomplish this without the use of javascript so it has to be done in xsl. Right now, I am looking at using a xsl:variable then attempting to use the xsl:when to do the compare. Unfortunately, I am having little luck. This is what I have just started playing with for each row in the table:
<xsl:variable name="compare" select="//main/comparer" />
...
<xsl:for-each select="value">
<td>
<xsl:choose>
<xsl:when test=". = $compare">
<b>
<xsl:value-of select="."/>
</b>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>.
</xsl:otherwise>
</xsl:choose>
</td>
</xsl:for-each>
*Note: I left out most of the xsl for brevity. I'm just trying to focus on my issue.
I figured it out after some trial and error. Alejandro's answer appears that it would work, but I do not have the luxury of restructuring the xsl to make use of templating. Here is what I used to solve my issue:
<xsl:variable name="compare" select="//main/comparer" />
...
<xsl:for-each select="value">
<td>
<xsl:choose>
<xsl:when test="contains(., $expireDate)">
<b>
<xsl:value-of select="."/>
</b>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>.
</xsl:otherwise>
</xsl:choose>
</td>
</xsl:for-each>
This stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="main">
<table>
<xsl:apply-templates select="items"/>
</table>
</xsl:template>
<xsl:template match="item">
<tr>
<xsl:apply-templates/>
</tr>
</xsl:template>
<xsl:template match="name|value">
<td>
<xsl:apply-templates/>
</td>
</xsl:template>
<xsl:template match="value/text()[.=/main/comparer]">
<b>
<xsl:value-of select="."/>
</b>
</xsl:template>
</xsl:stylesheet>
Output:
<table>
<tr>
<td>blarg</td>
<td>
<b>1</b>
</td>
<td>2</td>
</tr>
</table>
Note: Pattern matching and node set comparison.