Using Xsl-Key and generate-id() function - xslt

I would associate at the first IMG the first ATTACHED_FILENAME and
at the second IMG the second attached filename.
This is my XML:
<INSTRUCTION_LIST_ITEM>
<NTC_SD_INSTRUCT>
<ACTION>Sostituire</ACTION>
<PLACEMENT>le righe 10 ÷ 18 con:</PLACEMENT>
<DESCRIPTION>
<P>Il porto è protetto da un molo foraneo.</P>
<P>
<IMG border="0" hspace="0" alt="" align="baseline" src="C:\Users\l_sturla\Desktop\albany.jpg"/>
</P>
<P>Ben visibile da nord è il faro della Vittoria.</P>
<P>
<IMG border="0" hspace="0" alt="" align="baseline" src="C:\Users\l_sturla\Desktop\Faro vittoria.JPG"/>
</P>
<P> </P>
<P>Mantenersi a distanza di sicurezza.</P>
</DESCRIPTION>
<ATTACHMENT_LIST>
<ATTACHMENT>
<ATTACHED_FILENAME>albany.jpg</ATTACHED_FILENAME>
</ATTACHMENT>
<ATTACHMENT>
<ATTACHED_FILENAME>Faro vittoria.JPG</ATTACHED_FILENAME>
</ATTACHMENT>
</ATTACHMENT_LIST>
</NTC_SD_INSTRUCT>
</INSTRUCTION_LIST_ITEM>
I create this XSLT:
<xsl:template match="//IMG">
<span style="font-style:italic">
<xsl:choose>
<xsl:when test="count(ancestor::DESCRIPTION//IMG) = count(ancestor::DESCRIPTION/following-sibling::ATTACHMENT_LIST/ATTACHMENT/ATTACHED_FILENAME)">
<img>
<xsl:attribute name="src">
<xsl:value-of select="ancestor::NTC_SD_INSTRUCT/ATTACHMENT_LIST/ATTACHMENT/ATTACHED_FILENAME"/>
</xsl:attribute>
</img>
</xsl:when>
</xsl:choose>
</span>
</xsl:template>
But this give always the first image. ATTACHED_FILENAME tag is the parameter of attribute SRC.

Try
<xsl:template match="IMG">
<xsl:variable name="counter">
<xsl:number level="any" from="DESCRIPTION"/>
</xsl:variable>
<img src="{(//ATTACHED_FILENAME)[number($counter)]}"/>
</xsl:template>

If you define a key <xsl:key name="attachment-by-pos" match="NTC_SD_INSTRUCT/ATTACHMENT_LIST/ATTACHMENT" use="concat(generate-id(ancestor::NTC_SD_INSTRUCT), '|', count(preceding-sibling::ATTACHMENT))"/>, then you can use a template
<xsl:template match="IMG">
<span style="font-style:italic">
<img src="{key('attachment-by-pos', concat(generate-id(ancestor::NTC_SD_INSTRUCT), '|', count(../preceding-sibling::*//IMG)))/ATTACHED_FILENAME}"/>
</span>
</xsl:template>

Related

xslt - Date Format

I'm having some issue with my xslt code and I was Wondering if someone could take a look. I think the problem is with the date formatting but i'm not sure.
I need to format a datetime into a day and month.
this is my code:
<xsl:stylesheet
version="1.0"
exclude-result-prefixes="x d xsl msxsl cmswrt"
xmlns:x="http://www.w3.org/2001/XMLSchema"
xmlns:d="http://schemas.microsoft.com/sharepoint/dsp"
xmlns:cmswrt="http://schemas.microsoft.com/WebParts/v3/Publishing/runtime"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime">
<xsl:template name="NewsAndEvents" match="Row[#Style='NewsAndEvents']" mode="itemstyle">
<xsl:variable name="SafeImageUrl">
<xsl:call-template name="OuterTemplate.GetSafeStaticUrl">
<xsl:with-param name="UrlColumnName" select="'ImageUrl'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="DisplayTitle">
<xsl:call-template name="OuterTemplate.GetTitle">
<xsl:with-param name="Title" select="#Title"/>
<xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="ArticleDate">
<xsl:value-of select="#SongDate"/>
</xsl:variable>
<xsl:if test="string-length($SafeImageUrl) != 0">
<div class="event-contain">
<div class="event-img pull-right">
<div class="white-box">
<h1><xsl:value-of select="ddwrt:FormatDate(string($ArticleDate),1037, 'MMMM')"/></h1>
<h2><xsl:value-of select="ddwrt:FormatDate(string($ArticleDate),1037, 'd')"/></h2>
</div>
<img src="{$SafeImageUrl}" title="{#ImageUrlAltText}">
<xsl:if test="$ImageWidth != ''">
<xsl:attribute name="width">
<xsl:value-of select="$ImageWidth" />
</xsl:attribute>
</xsl:if>
<xsl:if test="$ImageHeight != ''">
<xsl:attribute name="height">
<xsl:value-of select="$ImageHeight" />
</xsl:attribute>
</xsl:if>
</img>
</div>
<div class="text-sec pull-right">
<header>
<hgroup>
<h3 class="ttl md fnt-bld blue"> <xsl:value-of select="$DisplayTitle"/> </h3>
<h4 class="ttl sm fnt-bld blue-mob"> <xsl:value-of select="#SongDescription"/> </h4>
</hgroup>
</header>
<div class="row dynamic-text-contain pull-right">
<p class="ttl xs">
<span class="display-on-mob"><xsl:value-of select="#NewsDescription" /></span>
</p>
</div>
<div class="row">
<div class="display-all read-more-eruim no-mob">
<div class="display-more open-link">
<a>
<i class="icon-icons2-50"></i>
<p>
<span class="btn-text">Show All</span>
<i class="icon-icons2-10 left-arrow" id="arrow"></i>
</p>
</a>
</div>
</div>
</div>
</div>
<div class="clearfix"></div>
<div class="line"></div>
</div>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Tnx For the Help Yotam.
I Have a Solution If any one ever has this problem:
the thing is that:
<xsl:value-of select="ddwrt:FormatDate(string($ArticleDate),1037, 'd')"/>
is the wrong syntax and should be :
<xsl:value-of select="ddwrt:FormatDateTime(string($ArticleDate),1037, 'd')"/>
Now, another thing is that it returns the value as: dd/mm/yyyy and I only wanted the day so I used a sub string function like so:
<xsl:value-of select="substring-before(ddwrt:FormatDateTime(string($ArticleDate),1037, 'd'),'/')"/>
This Solved me this issue :)

Last element of this group of node xslt

XML data :
<SECTION_CONTENT_LIST_ITEM>
<NTC_NAV3>
<IMMUTABLE_ID>5786
</IMMUTABLE_ID>
<INSTRUCTION_LIST>
<INSTRUCTION_LIST_ITEM>
<NTC_NAV3INSTRUCT>
<DESCRIPTION>
<P>descrzione breve di una storia</P>
</DESCRIPTION>
</NTC_NAV3INSTRUCT>
</INSTRUCTION_LIST_ITEM>
</INSTRUCTION_LIST>
</NTC_NAV3>
</SECTION_CONTENT_LIST_ITEM>
<SECTION_CONTENT_LIST_ITEM>
<NTC_NAV3>
<IMMUTABLE_ID>5787
</IMMUTABLE_ID>
<INSTRUCTION_LIST>
<INSTRUCTION_LIST_ITEM>
<NTC_NAV3INSTRUCT>
<DESCRIPTION>
<P>descriviamo in questo capitolo qualcosa</P>
</DESCRIPTION>
</NTC_NAV3INSTRUCT>
</INSTRUCTION_LIST_ITEM>
</INSTRUCTION_LIST>
</NTC_NAV3>
</SECTION_CONTENT_LIST_ITEM>
XSL:
<xsl:for-each select="SECTION_CONTENT_LIST">
<xsl:for-each select="SECTION_CONTENT_LIST_ITEM">
<xsl:sort select="NTC_NAV3/IMMUTABLE_ID" data-type="text" order="ascending"/>
<xsl:for-each select="NTC_NAV3">
<div style="text-align:left; border-top:2px solid black;">
<span style="line-height:normal; text-align:center; ">
<xsl:value-of select=".//NTC_NAV3INSTRUCT/DESCRIPTION"/>
</span>
</div>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
In output I would only the output :
descriviamo in questo capitolo qualcosa
this is the last description orderd by immutable_id
You could use
<xsl:for-each select="SECTION_CONTENT_LIST">
<xsl:for-each select="SECTION_CONTENT_LIST_ITEM">
<xsl:sort select="NTC_NAV3/IMMUTABLE_ID" data-type="text" order="ascending"/>
<xsl:for-each select="NTC_NAV3[last()]">
<div style="text-align:left; border-top:2px solid black;">
<span style="line-height:normal; text-align:center; ">
<xsl:value-of select=".//NTC_NAV3INSTRUCT/DESCRIPTION"/>
</span>
</div>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
assuming you only want to process the last NTC_NAV3 element.
If that does not help then consider to show a sample of the XML input and the corresponding HTML output you want to create with XSLT.

xsl 1.0, count if more than 2 elements then change css class

The data comes from the server, usually two rows, but sometimes it's more. So I try to make the list dynamic change.
<xsl:template match="Event">
<ul class="lines">
<xsl:apply-templates select="Line"/>
</ul>
</xsl:template>
<xsl:template match="Line">
<li class="something">
<a href="">
<span class="result"><xsl:value-of select="#result"/></span>
<span class="odds"><xsl:value-of select="#odds"/></span>
</a>
</li>
</xsl:template>
I have to count the number of "li" and if it's more than 2, i have to change the class of "li"
Within the template matching Line you can access the total number of Line elements within this Event using the last() function (which returns the index number of the last node in the "current node list" determined by the select expression of the apply-templates that caused this template to fire, which in this case is the set of Line children of a particular Event).
<li>
<xsl:attribute name="class">
<xsl:choose>
<xsl:when test="last() <= 2">something</xsl:when>
<xsl:otherwise>somethingElse</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
How about something like this:
<xsl:template match="Event">
<ul class="lines">
<xsl:apply-templates select="Line"/>
</ul>
</xsl:template>
<xsl:template match="Line" name="Line">
<xsl:param name="classVal" select="'something'" />
<li class="{$classVal}">
<a href="">
<span class="result">
<xsl:value-of select="#result"/>
</span>
<span class="odds">
<xsl:value-of select="#odds"/>
</span>
</a>
</li>
</xsl:template>
<xsl:template match="Line[count(../Line) > 1]">
<xsl:call-template name="Line">
<xsl:with-param name="classVal" select="'somethingElse'" />
</xsl:call-template>
</xsl:template>

content query webpart itemstyle wrapped by group style in XSLT

I have the following markup:
<ul id="slider">
<!-- slider item -->
<li>
...
</li>
<!-- end of slider item -->
</ul>
and I have defined the following itemStyle and GroupStyle xsl in header.xsl and itemStyle.xsl for displaying data from a SharePoint 2010 List:
<!-- in header.xsl -->
<xsl:template name="Slider" match="*[#GroupStyle='Slider']" mode="header">
<ul id="slider">
</ul>
</xsl:template>
<!-- in itemStyle.xsl -->
<xsl:template name="Slider" match="Row[#Style='Slider']" mode="itemstyle">
<xsl:variable name="SafeImageUrl">
<xsl:call-template name="OuterTemplate.GetSafeStaticUrl">
<xsl:with-param name="UrlColumnName" select="#Picture"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="Title">
<xsl:call-template name="OuterTemplate.GetTitle">
<xsl:with-param name="Title" select="#Title" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="Details">
<xsl:call-template name="OuterTemplate.GetTitle">
<xsl:with-param name="Title" select="#Details" />
</xsl:call-template>
</xsl:variable>
<li>
<img src="{$SafeImageUrl}" alt="{$Title}" />
<section class="media-description">
<h2 class="slider-headline"><xsl:value-of disable-output-escaping="yes" select="$Title" /></h2>
<p><xsl:value-of disable-output-escaping="yes" select="$Details" /></p>
</section>
</li>
</xsl:template>
but the thing is, when applying the previous two templates, the <ul id="slider"></ul> appears isolated from all <li> items as below:
<ul id="slider"></ul>
<!-- a bunch of tables and td here.. -->
<ul style="width: 100%;" class="dfwp-column dfwp-list">
<li class="dfwp-item"></li>
<li>
<img alt="Must-see US exhibitions" src="">
<section class="media-description"><h2 class="slider-headline">Must-see US exhibitions</h2>
<p>(Blank)</p>
</section>
</li>
...
</ul>
all I want is to have <ul id="slider>" element to wrap those li's directly,
so how can i do that ?
Thanks
What's your input XML?
You'd do something like this:
<xsl:template name="Slider" match="*[#GroupStyle='Slider']" mode="header"><!-- Sure you want to match *? -->
<ul id="slider">
<!-- Match the input XML path to your rows from the context of the matched element above -->
<xsl:apply-templates select="Row[#Style='Slider']" mode="itemstyle" />
</ul>
</xsl:template>
<xsl:template name="Slider" match="Row[#Style='Slider']" mode="itemstyle">
<li>..</li>
</xsl:template>
Can't figure out why you are using "mode"s either.
problem solved, thanks to #James Love,
and here are the steps:
make a copy of ContentQueryMain.xsl, as the following article says
after having a copy of ContentQueryMain.xsl, edit it and look for OutTemplate.Body
then you can place your wrapper in the following variables (but they have to be escaped)
<xsl:template name="OuterTemplate.Body">
<xsl:variable name="BeginColumn1" select="string('<ul id="slider" class="dfwp-column dfwp-list" style="width:')" />
<!-- ^------------------^ -->
<xsl:variable name="BeginColumn2" select="string('%" >')" />
<xsl:variable name="BeginColumn" select="concat($BeginColumn1, $cbq_columnwidth, $BeginColumn2)" />
<xsl:variable name="EndColumn" select="string('</ul>')" />
<!-- ^---------^ -->
stupid workaround, but its working :S

XSLT: trying to do a contains() with a full XPath. Why does this fail?

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" />
<xsl:template match="/">
<html>
<body>
<span>
<div style="background-color:#000066;color:#EEEEEE;padding:7px">
<a name="top" style="padding-left:10px;font-size:28pt">Alerting Variables</a>
</div>
</span>
<div style="display:block;padding-left:50px;padding-bottom:10px" class="hbuttons">
LDMS Alerts
LDSM Alerts
Why?
Examples
Resources
</div>
<div style="clear: left;"></div>
<!-- This is the Table of Contents-->
<div style="padding:5px">
<div style="padding:5px;margin-top:10pt;margin-bottom:10pt;font-weight:bold;font-size:20px">Table of Contents -
<a style="position:absolute;margin-left:40px" href="PrintPages/PrintAll.html">
<img border="0" src="images/PrintButton.png" />
</a></div>
<div style="font-family:Arial;font-weight:bold;margin-left:30px;font-size:10pt">
<xsl:if test="contains(identifiers/sectionname/alert/#name, 'Agent Watcher')">
Agent Watcher
<a style="position:absolute;margin-left:40px" href="PrintPages/PrintAW.html">
<img border="0" src="images/PrintButton.png" />
</a>
</xsl:if>
<ol style="margin-top:5">
<xsl:for-each select="identifiers/sectionname/alert">
<xsl:if test="contains(#name, 'Agent Watcher')">
<li style="margin-left:10pt;font-size:8pt">
<a>
<xsl:attribute name="href">#
<xsl:value-of select="#name" /></xsl:attribute>
<xsl:value-of select="#name" />
</a>
</li>
</xsl:if>
</xsl:for-each>
</ol>
</div>
<div style="font-family:Arial;font-weight:bold;margin-left:30px;font-size:10pt">
Intel vPro
<a style="position:absolute;margin-left:40px" href="PrintPages/PrintvPro.html">
<img border="0" src="images/PrintButton.png" />
</a>
<ol style="margin-top:5">
<xsl:for-each select="identifiers/SectionName/alert">
<xsl:if test="contains(#name, 'Intel vPro')">
<li style="margin-left:10pt;font-size:8pt">
<a>
<xsl:attribute name="href">#
<xsl:value-of select="#name" /></xsl:attribute>
<xsl:value-of select="#name" />
</a>
</li>
</xsl:if>
</xsl:for-each>
</ol>
</div>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Above is my code sample.
The first xsl:if statement always fails and never shows the Agent Watcher text or print me button. Even if the section is filled out in the XML. If the section is there, the first xsl:if statement fails, but the second one, contained in the xsl:for-each shows the content. How do I get this to work.
I want to have it encompassing so that if the XML has content in the section it will put it up but if not it wont be empty content with a header or vice versa. Attaching sample XML to process.
<identifiers>
<sectionname>
<alert name="Agent Watcher Service Startup"></alert>
<alert name="Agent Watcher Service Not Started"></alert>
<alert name="Agent Watcher Service Uninstalled"></alert>
<alert name="Agent Watcher File Deleted"></alert>
</sectionname>
<sectionname>
<alert name="Intel vPro agentless discovery failure"></alert>
<alert name="Intel vPro System Defense Remediation Alert"></alert>
<alert name="Intel vPro Enhanced System Defense Remediation Alert"></alert>
<alert name="Intel vPro Enhanced System Defense Alert"></alert>
</sectionname>
</identifiers>
Blockquote
I have a few other suggestions but you need to post the entire (relevant) XSLT before I can go on. At least the enclosing template is necessary.
EDIT: Here is my proposal for your stylesheet:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:tmp="http://tempuri.org"
exclude-result-prefixes="tmp"
>
<tmp:config>
<tmp:alert label="Agent Watcher" link="PrintPages/PrintAW.html" />
<tmp:alert label="Intel vPro" link="PrintPages/PrintvPro.html" />
</tmp:config>
<xsl:variable name="everyAlert" select="
/identifiers/sectionname/alert
" />
<xsl:template match="/">
<html>
<body>
<!-- 8< snip -->
<div style="...">
<div style="...">
<xsl:text>Table of Contents - </xsl:text>
<a style="..." href="PrintPages/PrintAll.html">
<img border="0" src="images/PrintButton.png" />
</a>
</div>
<xsl:for-each select="document('')/*/tmp:config/tmp:alert">
<xsl:call-template name="section" />
</xsl:for-each>
</div>
</body>
</html>
</xsl:template>
<xsl:template name="section">
<xsl:variable name="this" select="." />
<xsl:variable name="alerts" select="
$everyAlert[contains(#name, $this/#label)]
" />
<xsl:if test="$alerts">
<div style="...">
<a href="#{translate($this/#label, ' ', '_')}">
<xsl:value-of select="$this/#label" />
</a>
<a style="..." href="{$this/#link}">
<img border="0" src="images/PrintButton.png" />
</a>
<ol style="...">
<xsl:for-each select="$alerts">
<li style="...">
<xsl:value-of select="#name" />
</li>
</xsl:for-each>
</ol>
</div>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Key features:
efficient code reuse through a named template
printed sections are easily configurable
uses <xsl:text> elements to avoid unwanted whitespace in the output while retaining freedom to format the XSLT code properly
uses attribute literal notation (the curly braces {}) instead of verbose <xsl:attribute> elements
uses a temporary namespace to allow storing config data in the stylesheet itself
uses an <xsl:for-each> loop and the document() function to retrieve and work with that config data
the for-each makes use of the context to transport the current #label and #link so no <xsl:param> is necessary (the <xsl:template name="section"> runs in tmp:config/tmp:alert context, not in sectionname/alert context!)
uses a global variable ($everyAlert) to store all nodes for later use