For the below simplified transformation sheet, I'd like to add the following functions:
For "Turnover 2019" and "Turnover 2020" I'd like to get the values below 1mio in a red badge and over 1mio in a green badge. I tried to implement this for "Turnover 2019", however I just get a blank output. The problem seems to be with the <xsl:if test="...">-part, as I do get the correct value if I just enter <xsl:value-of select="key('keyToCreditcard', id)/turnover_2019"/> (see "Turnover 2020").
For "Total Turnover" I need to sum up the values of "Turnover 2019" and "Turnover 2020". How do I do that?
XSL:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="keyToPerson" match="person" use="id"/>
<xsl:key name="keyToCreditcard" match="creditcard" use="cardowner"/>
<xsl:template match="/">
<xsl:for-each select="data/persons/person">
<xsl:if test="turnoverYear1 < 1000000">
<span class="badge bg-warning mx-2"><xsl:value-of select="key('keyToCreditcard', id)/turnoverYear1"/></span>
</xsl:if>
<xsl:if test="turnoverYear1 > 999999.99">
<span class="badge bg-danger mx-2"><xsl:value-of select="key('keyToCreditcard', id)/turnoverYear1"/></span>
</xsl:if>
<xsl:value-of select="key('keyToCreditcard', id)/turnoverYear2"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Input:
<data>
<persons>
<person>
<id>1</id>
<name>Jeramie Bischoff</name>
<city>Luzern</city>
<birthdate>04/16/1951</birthdate>
</person>
</persons>
<creditcards>
<creditcard>
<id>1</id>
<cardtype>Visa</cardtype>
<cardnumber>4041592612048990</cardnumber>
<turnoverYear1>952411.33</turnoverYear1>
<turnoverYear2>6135840.0</turnoverYear2>
<cardowner>1</cardowner>
</creditcard>
</creditcards>
</data>
Expected Output:
Name:Jeramie Bischoff
City: Luzern
birthdate: 04/16/1951
Card Type: Visa
Card Number: 4041592612048990
Turnover 2019: 952411.33
Turnover 2020: 6135840.0
Total Turnover: 7088251.33
Based on your sample XML, a good approach would be to split things up into multiple templates.
One to handle creating the basic HTML document structure (match="/"), one to handle <person> elements, one to handle the turnover badges, and so on. In general it's beneficial to prefer <xsl:apply-templates> over cramming everything into a single template with a bunch of nested <xsl:for-each>.
Since you have an <xsl:key> that links person IDs to credit cards, use that to fetch the <creditcard> into a variable ($cc) and work with it.
<xsl:output method="html" indent="yes" />
<xsl:key name="keyToCreditcard" match="creditcard" use="cardowner"/>
<xsl:template match="/">
<html>
<!-- ... -->
<xsl:apply-templates select="data/persons/person" />
<!-- ... -->
</html>
</xsl:template>
<xsl:template match="person">
<div class="person">
<xsl:variable name="cc" select="key('keyToCreditcard', id)" />
<!-- your question #1 -->
<div>
<xsl:text>Turnover 2019: </xsl:text>
<xsl:apply-templates select="$cc/turnoverYear1" />
</div>
<div>
<xsl:text>Turnover 2020: </xsl:text>
<xsl:apply-templates select="$cc/turnoverYear2" />
</div>
<!-- your question #2 -->
<div>
<xsl:text>Total Turnover: </xsl:text>
<xsl:value-of select="$cc/turnoverYear1 + $cc/turnoverYear2" />
</div>
</div>
</xsl:template>
<xsl:template match="turnoverYear1|turnoverYear2">
<span>
<xsl:attribute name="class">
<xsl:text>badge mx-2 </xsl:text>
<xsl:choose>
<xsl:when test=". < 1000000">bg-warning</xsl:when>
<xsl:when test=". < 99999.99">bg-danger</xsl:when>
</xsl:choose>
</xsl:attribute>
<xsl:value-of select="." />
</span>
</xsl:template>
which results in
<html>
<div class="person">
<div>Turnover 2019: <span class="badge mx-2 bg-warning">952411.33</span></div>
<div>Turnover 2020: <span class="badge mx-2">6135840.0</span></div>
<div>Total Turnover: 7088251.33</div>
</div>
</html>
Because the year numbers and XML element names are a moving target in your XML, you would have to keep adjusting the XSLT code every year. That's completely unnecessary. It's a lot smarter to keep the year out of the XML element names. Move it into an attribute:
<creditcards>
<creditcard>
<id>1</id>
<cardtype>Visa</cardtype>
<cardnumber>4041592612048990</cardnumber>
<turnover year="2019">952411.33</turnover>
<turnover year="2020">6135840.0</turnover>
<cardowner>1</cardowner>
</creditcard>
</creditcards>
With a <creditcard> setup like this, the XSLT code gets more generic.
<xsl:template match="person">
<div class="person">
<xsl:variable name="cc" select="key('keyToCreditcard', id)" />
<!-- your question #1 -->
<xsl:apply-templates select="$cc/turnover" />
<!-- your question #2 -->
<div>
<xsl:text>Total Turnover: </xsl:text>
<xsl:value-of select="sum($cc/turnover)" />
</div>
</div>
</xsl:template>
<xsl:template match="turnover">
<div>
<xsl:value-of select="concat('Turnover ', #year, ': ')" />
<span>
<xsl:attribute name="class">
<xsl:text>badge mx-2 </xsl:text>
<xsl:choose>
<xsl:when test=". < 1000000">bg-warning</xsl:when>
<xsl:when test=". < 99999.99">bg-danger</xsl:when>
</xsl:choose>
</xsl:attribute>
<xsl:value-of select="." />
</span>
</div>
</xsl:template>
Related
below is my XML which consist below nodes.
<richtext >
<par def="3">
paragraph value 1
<run>
<font style="underline" />run value 1
</run>.
paragraph value 2
<run>
<font style="underline" />run value 2
</run>
paragraph value 3
<run>
<font style="underline" />run value 2 <br /> run value on new line
</run>
paragraph value 4
</par>
</richtext>
i am transforming above xml to html using below xslt. i am new to xslt please help me.
<xsl:template match="/">
<div>
<xsl:apply-templates select="richtext" />
</div>
<xsl:template name="richtext">
<xsl:apply-templates select="par" />
<xsl:apply-templates select="table" />
<xsl:template match="par">
<p>
<xsl:if test="text()">
<xsl:value-of disable-output-escaping="yes" select="text()" />
<xsl:value-of disable-output-escaping="yes" select="*/following-sibling::text()" />
</xsl:if>
<xsl:if test="run">
<xsl:apply-templates select="run" />
<xsl:value-of disable-output-escaping="yes" select="run/following-sibling::text()" />
</xsl:if>
</p>
<xsl:template match="run">
<span>
<xsl:call-template name="style" />
<xsl:value-of disable-output-escaping="yes" select="current()" />
</span>
i want below html output
<p>
paragraph value 1
<span style="underline">
run value 1
</span>.
paragraph value 2
<span style="underline">
run value 2 <br /> run value on new line
</span>
paragraph value 3
<span style="underline">
run value 2
</span>
paragraph value 4
</p>
Please see updated HTML output. can you please tell me what to do ? i want to preserve style from xml.
Edit : if we add in XML then i want text after on new line in HTML.
It looks like you want to do the following:
Convert richtext to div
Convert par to p
Convert run to span
Convert font to an attribute
In which case, a series of simple templates should do it.
Try this XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" indent="yes" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="richtext">
<div>
<xsl:apply-templates select="par|table" />
</div>
</xsl:template>
<xsl:template match="par">
<p>
<xsl:apply-templates />
</p>
</xsl:template>
<xsl:template match="run">
<span>
<xsl:call-template name="style" />
<xsl:apply-templates />
</span>
</xsl:template>
<xsl:template match="font" />
<xsl:template name="style">
<xsl:attribute name="style">
<xsl:for-each select="font">
<xsl:if test="position() > 1">; </xsl:if>
<xsl:value-of select="#style" />
</xsl:for-each>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Note the template matching "font" isn't really necessary here. As the font elements in your example have no child, you could omit the template as the built-in templates will just skip over it, and output nothing.
I want to add a new tag <br\> to my XML each 10 characters. (without including inner nodes)
For example if my input is:
<main>
01234567890123
<a>
link
</a>
45678901234567901234
</main>
I expect is to be somthing like:
<main>
0123456789<br\>0123
<a>
link
</a>
456789<br\>012345679<br\>01234
</main>
I wrote this function:
<!-- Add new "HTML Break" Every X chars -->
<xsl:template name="Add-HTML-Break-After-X-Chars">
<xsl:param name="text" />
<xsl:param name="max-length" />
<xsl:choose>
<xsl:when test="string-length($text) > $max-length">
<!-- Show the X length of the text -->
<xsl:copy-of select="substring($text,1,$max-length)" />
<!-- Adding the special tag -->
<br/>
<!-- continue to add the rest of the text -->
<xsl:call-template name="Add-HTML-Break-After-X-Chars">
<xsl:with-param name="text" select="substring($text, $max-length + 1)" />
<xsl:with-param name="max-length" select="$max-length" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<!-- Show the text (length is less then X) -->
<xsl:copy-of select="$text" />
</xsl:otherwise>
</xsl:choose>
The problem is that I'm getting the output without the inner tags:
<main>
0123456789<br\>0123
link
45<br\>6789012345<br\>67901234
</main>
I'm using this code to call the template:
<xsl:call-template name="Add-HTML-Break-After-X-Chars">
<xsl:with-param name="text" select="main" />
<xsl:with-param name="max-length" select="10" />
</xsl:call-template>
I tried also "value-of" instead of "copy-of".
Is there a way I can keep the tags?
If so, how can I keep them and make a "safe" insert of the new tag?
This is difficult to do in XSLT, because it processes each text node individually, with no information being carried over from the preceding text nodes.
Here's a possible approach:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="main/text()" name="wrap">
<xsl:param name="text" select="."/>
<xsl:param name="line-length" select="10"/>
<xsl:param name="carry">
<xsl:variable name="lengths">
<xsl:for-each select="preceding-sibling::text()">
<length>
<xsl:value-of select="string-length()"/>
</length>
</xsl:for-each>
</xsl:variable>
<xsl:value-of select="sum(exsl:node-set($lengths)/length) mod $line-length"/>
</xsl:param>
<xsl:value-of select="substring($text, 1, $line-length - $carry)"/>
<br/>
<xsl:if test="$carry + string-length($text) > $line-length">
<!-- recursive call -->
<xsl:call-template name="wrap">
<xsl:with-param name="text" select="substring($text, $line-length - $carry + 1)"/>
<xsl:with-param name="carry" select="0"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
When this is applied to the following test input:
XML
<main>A123456789B123<a>link1</a>456789C123456789D12345678<a>link2</a>9E123456789F1234567</main>
the result will be:
<?xml version="1.0" encoding="UTF-8"?>
<main>A123456789<br/>B123<a>link1</a>456789<br/>C123456789<br/>D12345678<a>link2</a>9<br/>E123456789<br/>F1234567</main>
Coming from this XML :
<log>
<found>
<color bgcolor="red">This is a silly <u>dummy</u> text with <color color="green">colored</colored> words and some <b>emphasized</b> ones</color>
</found>
<notfound>
This is a silly <color color="red">stupid</color> text
</notfound>
</log>
I must produce this HTML :
<p>Found : <pre><span style="background-color:red;">This is a silly <u>dummy</u> text with <span style="color:green;">colored</span> words and some <b>emphasized</b> ones</span></pre></p>
<p>Not Found : <pre>This is a silly <span style="color:red;">stupid</span> text</pre></p>
I tried to achieve this with :
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="UTF-8"/>
<xsl:apply-templates select="/log"/>
<xsl:template match="log">
<xsl:apply-templates select="found"/>
<xsl:apply-templates select="notfound"/>
</xsl:template>
<xsl:template match="found">
<xsl:if test=". != ''">
<p>Found : <pre><xsl:apply-templates name="./color"/></pre></p>
</xsl:if>
</xsl:template>
<xsl:template match="notfound">
<xsl:if test=". != ''">
<p>Not found : <pre><xsl:apply-templates name="./color"/></pre></p>
</xsl:if>
</xsl:template>
<xsl:template match="*/color">
<span>
<xsl:attribute name="style">
<xsl:if test="./#color != ''">
color:<xsl:value-of select="./#color"/>;
</xsl:if>
<xsl:if test="./#bgcolor != ''">
background-color:<xsl:value-of select="./#bgcolor"/>;
</xsl:attribute>
<xsl:apply-templates select="./color"/>
<xsl:copy-of select="text()"/>
</span>
</xsl:template>
</xsl:stylesheet>
But it fails by stripping everything that may be within <u> or <b> or <i> it may found (see <found>) or putting every colored stuff before all other content (see <notfound>) :
<p>Found : <pre><span style="background-color:red;">This is a silly text with <span style="color:green;">colored</span> words and some ones</span></pre></p>
<p>Not Found : <pre><span style="color:red;">stupid</span>This is a silly text</pre></p>
Where am I wrong ?
Many thanks for any help !
I don't have version 2.0 available, but I was able to change it into a working 1.0 version. The important changes in the comments:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="UTF-8"/>
<xsl:template match="log">
<xsl:apply-templates select="found"/>
<xsl:apply-templates select="notfound"/>
</xsl:template>
<xsl:template match="found">
<xsl:if test=". != ''">
<p>Found : <pre><xsl:apply-templates/></pre></p>
</xsl:if>
</xsl:template>
<xsl:template match="notfound">
<xsl:if test=". != ''">
<p>Not found : <pre><xsl:apply-templates/></pre></p>
</xsl:if>
</xsl:template>
<xsl:template match="color">
<span>
<xsl:attribute name="style">
<xsl:if test="./#color != ''">color:<xsl:value-of select="./#color"/>;</xsl:if>
<xsl:if test="./#bgcolor != ''">background-color:<xsl:value-of select="./#bgcolor"/>;</xsl:if>
</xsl:attribute>
<!-- this is needed to process the inner tags -->
<xsl:apply-templates/>
</span>
</xsl:template>
<!-- This prints underlined and bold text. -->
<xsl:template match="*">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
As far as I see you want to:
change the <found> and <notfound> tags into string, plus add a <p> tag before, and a <pre> after
Change the <color bgcolor="red"> into <span style="color:red;"> and </color> into </span>
What I would do is use Beautiful Soup, iterate over the tags, and change them according to 1 and 2.
There have been similar questions but none working with SharePoint and the XSL editor.
I have an RSS feed which is pulling in article titles, along with accompanying html tags as shown below:
<i>Wall Street Journal</i> Article on Competition in the Dental Industry
I would like to have those <i> (and any other HTML tags) be read as HTML, not text..i.e an end result of:
Wall Street Journal Article on Competition in the Dental Industry
I can read and semi-reverse engineer XML, but writing it is another story.
Any help will be greatly appreciated.
A sample of my code where I think the changes is needed, below:
<xsl:template name="RSSMainTemplate.body" xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<xsl:param name="Rows"/>
<xsl:param name="RowCount"/>
<xsl:for-each select="$Rows">
<xsl:variable name="CurPosition" select="position()" />
<xsl:variable name="RssFeedLink" select="$rss_WebPartID" />
<xsl:variable name="CurrentElement" select="concat($RssFeedLink,$CurPosition)" />
<xsl:if test="($CurPosition <= $rss_FeedLimit)">
<div class="item link-item" >
<a href="{concat("javascript:ToggleItemDescription('",$CurrentElement,"')")}" >
<xsl:value-of select="title"/>
</a>
<xsl:if test="$rss_ExpandFeed = true()">
<xsl:call-template name="RSSMainTemplate.description">
<xsl:with-param name="DescriptionStyle" select="string('display:block;')"/>
<xsl:with-param name="CurrentElement" select="$CurrentElement"/>
</xsl:call-template>
</xsl:if>
<xsl:if test="$rss_ExpandFeed = false()">
<xsl:call-template name="RSSMainTemplate.description">
<xsl:with-param name="DescriptionStyle" select="string('display:none;')"/>
<xsl:with-param name="CurrentElement" select="$CurrentElement"/>
</xsl:call-template>
</xsl:if>
</div>
</xsl:if>
</xsl:for-each>
</xsl:template>
Figured it out.
The key to this issue is the disable-output-escaping attribute. I was correct about the location of the issue. Below is my adjusted code. Notice lines 10-15
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<xsl:param name="Rows"/>
<xsl:param name="RowCount"/>
<xsl:for-each select="$Rows">
<xsl:variable name="CurPosition" select="position()" />
<xsl:variable name="RssFeedLink" select="$rss_WebPartID" />
<xsl:variable name="CurrentElement" select="concat($RssFeedLink,$CurPosition)" />
<xsl:if test="($CurPosition <= $rss_FeedLimit)">
<div class="item link-item" >
<a href="{concat("javascript:ToggleItemDescription('",$CurrentElement,"')")}" >
<xsl:variable name="SafeHtml">
<xsl:call-template name="GetSafeHtml">
<xsl:with-param name="Html" select="title"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="$SafeHtml" disable-output-escaping="yes"/>
</a>
<xsl:if test="$rss_ExpandFeed = true()">
<xsl:call-template name="RSSMainTemplate.description">
<xsl:with-param name="DescriptionStyle" select="string('display:block;')"/>
<xsl:with-param name="CurrentElement" select="$CurrentElement"/>
</xsl:call-template>
</xsl:if>
<xsl:if test="$rss_ExpandFeed = false()">
<xsl:call-template name="RSSMainTemplate.description">
<xsl:with-param name="DescriptionStyle" select="string('display:none;')"/>
<xsl:with-param name="CurrentElement" select="$CurrentElement"/>
</xsl:call-template>
</xsl:if>
</div>
</xsl:if>
</xsl:for-each>
<div class="description">
<h4 class="ms-rteElement-H4B">
<span class="ms-rteStyle-Emphasis">
<br></br>View More Articles <img alt="more-icon-1.png" src="/BHiveImageGallery/Stock-Images/more-icon-1.png"/>
</span>
<span class="ms-rteStyle-Emphasis"> </span>
</h4>
</div>
My full code is too long and formatted too uniquely to get it to display as I want in the window. It is 3/20/2015 right now, if you message me within the next 5 years i'll be able to send you the code, beyond that, no guarantees haha.
Generally though I used the SharePoint 2013 standard RSS viewer webpart code, and only modified the piece above
How to complete the following style sheet that should produce HTML output in figure 1.
I have styled some part of it but could not make it exactly the same as in figure 1. I have tried "copy element" in XSL but gave me duplicate results.
This is my XML:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="research.xsl"?>
<ResearchGroups xmlns="http://www.sam.com/sam.html">
<Group name="Intelligent Systems Group" id="ISG"> The Intelligent
Systems Group pursues internationally-leading research in a wide
range of intelligent systems. </Group>
<Group name="Robotics" id="RBT"> The Essex robotics group is one of
the largest mobile robotics groups in the UK. </Group>
<Staff name="Callaghan, Vic" title="Professor" groups="ISG RBT">
Intelligent environments and robotics. </Staff>
<Staff name="Gu, Dongbing" title="Dr" groups="RBT"> Multi-agent
and distributed control systems. </Staff>
</ResearchGroups>
My XSLT:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:rg="http://www.sam.com/sam.html"
xmlns="http://wwww.w3.org/1999/xhtml"
version="2.0"> <xsl:template match="/">
<html>
<head> <title>Research Groups</title> </head>
<body> <xsl:apply-templates select="//rg:Group"/> </body>
</html> </xsl:template> <xsl:template match="rg:Group">
<xsl:variable name="ID" select="#id"/>
<h3> <a name="{$ID}"> <xsl:value-of select="#name"/> </a> </h3>
<p> <xsl:value-of select="text()"/> </p>
</xsl:template>
</xsl:stylesheet>
HTML Figure 1
the XSLT style sheet should output the following HTML
Something like this I think:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:rg="http://www.sam.com/sam.html" xmlns="http://wwww.w3.org/1999/xhtml" version="2.0">
<xsl:template match="/">
<html>
<head>
<title>Research Groups</title>
</head>
<body>
<xsl:apply-templates select="//rg:Group"/>
</body>
</html>
</xsl:template>
<xsl:template match="rg:Group">
<xsl:variable name="ID" select="#id"/>
<h3>
<a name="{$ID}">
<xsl:value-of select="#name"/>
</a>
</h3>
<p>
<xsl:value-of select="text()"/>
</p>
<ul>
<xsl:apply-templates select="//rg:Staff[contains(#groups, current()/#id)]">
<xsl:with-param name="curGroup"><xsl:value-of select="#id"/></xsl:with-param>
</xsl:apply-templates>
</ul>
</xsl:template>
<xsl:template match="rg:Staff">
<xsl:param name="curGroup"/>
<li>
<xsl:value-of select="#name"/>
<xsl:text>: </xsl:text>
<xsl:value-of select="text()"/>
<xsl:if test="//rg:Group[(#id != $curGroup) and contains(current()/#groups, #id)]">
<xsl:text> ( </xsl:text>
<xsl:apply-templates select="//rg:Group[(#id != $curGroup) and contains(current()/#groups, #id)]" mode="otherGroups"/>
<xsl:text> ) </xsl:text>
</xsl:if>
</li>
</xsl:template>
<xsl:template match="rg:Group" mode="otherGroups">
<a href="#{#id}">
<xsl:value-of select="#id"/>
</a>
</xsl:template>
</xsl:stylesheet>