xslt: remove space before and after specific elements - xslt-3.0

I'm using Saxon PE 9.7, XSLT version 3.0.
I try to remove space after <w> before <damage>. I have tried several solutions: normalize-space(), translate(., ' ', ''), even css, white-space: nowrap... I also looked to the solution proposed to How do I remove spaces in all attribute values using xslt?. Unfortunately, none worked.
TEI
<lg>
<!-- other <l> -->
<l>
<!-- other <w> -->
<w xml:id="ktu1-3_ii_l7_ym" type="noun" lemmaRef="uga/noun.xml#ym" rendition="#nowrap">y</w><damage agent="unknown"><supplied resp="KTU" rendition="#bracketBefore #bracketAfter"><w corresp="ktu1-3_ii_l7" type="part-of-noun">m</w></supplied></damage> <!-- type="part-of-noun" because I also have type="part-of-verb", and the display is different -->
</l>
</lg>
When I have damage/supplied/w before the second <w>, it works, but not after the first <w>
XSLT
<xsl:template match="lg/l[#n]">
<li>
<xsl:apply-templates/>
<sup style="font-size: 0.8em">
<xsl:value-of select="#n"/>
</sup>
</li>
</xsl:template>
<xsl:template match="lg/l[#n]/damage/supplied">
<xsl:choose>
<xsl:when test="#rendition">
<xsl:text>[</xsl:text>
<xsl:apply-templates select="./w[not(#rendition='notDisplay')]"/><xsl:text>]</xsl:text>
</xsl:when><xsl:otherwise><xsl:apply-templates select="./w[not(#rendition='notDisplay')]"/></xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="w">
<xsl:apply-templates select="normalize-space(.)"/>
</xsl:template>
<xsl:template match="lg/l[#n]/w">
<xsl:apply-templates select=".[#type= 'noun']" mode="css"/>
<xsl:apply-templates select="normalize-space(.)"/>
</xsl:template>
In advance, thank you for your kind advice.

I'm having trouble working out exactly what you want to achieve. What is the desired output? Are you talking about unwanted space in the visual rendition of the HTML, or about unwanted space in the XML/HTML transformation result?
Writing
<xsl:apply-templates select="normalize-space(.)"/>
is clearly wrong unless you have template rules that match atomic xs:string values, which seems unlikely. And neither of your <w> elements have any whitespace in their string-values, so normalize-space is a no-op anyway.

Related

Add '(apostrophe) as a valid character in XSLT template

I am working on a project there they have given a list of valid characters which should be passed as it is and any other characters other than them has to be replaced with ?(question mark).
My company software does not allows to use replace function, so i have to use translate method.
I am able to add all the valid characters except '(apostrophe). How to include apostrophe also as a valid character in variable vAllowedSymbols.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:variable name="vAllowedSymbols" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890/-?:(),.+ '"/>
<xsl:template match="node() | #*">
<xsl:copy>
<xsl:apply-templates select="node() | #*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()">
<xsl:value-of select="
translate(
.,
translate(., $vAllowedSymbols, ''),
''
)
"/>
</xsl:template>
Input:
<t>
<Name>#O'Niel</Name>
<Name>St: Peter</Name>
<Name>A.David</Name>
</t>
Output:
<t>
<Name>?O'Niel</Name>
<Name>St: Peter</Name>
<Name>A.David</Name>
</t>
Use
<xsl:variable name="vAllowedSymbols">ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890/-?:(),.+ '</xsl:variable>
<xsl:variable name="vAllowedSymbols" select='"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890/-?:(),.+ &apos;"'/>
There is some advantage in having the variable contain a string instead of a text node. Or more precisely, be a string instead of a node-set that contains a text node.

Remove the first elements of a path in XSLT

I'm trying to remove the first 3 'tokens' of a path-looking string in XSLT 2.0.
For instance, go from D:/FolderA/folderB/folderC/file.ext to folderC/file.ext.
I cant find a quick idea to do it other than using a recursive function I'm struggling to write.
<xsl:variable name="tokenizedPath" select="(tokenize($url,'/'))" />
<xsl:value-of select="yy:restofpath($tokenizedPath,2)" />
where yy:restofpath could be something like:
<xsl:function name="yy:restofpath" as="xs:string">
<xsl:param name="pathtokens"/>
<xsl:param name="startIndex"/>
<xsl:variable name="length" select="count($pathtokens)"/>
<xsl:for-each select="$pathtokens">
<xsl:value-of select="string-join(.,yy:restofpath($pathtokens,),'')"/>
</xsl:for-each>
</xsl:function>
This is a dumb function that I cant write, I'm confused how to process my tokenized string.
Maybe there is a simpler built-in way to do that?
Given:
<xsl:variable name="tokenizedPath" select="tokenize($url,'/')" />
then you can use:
<xsl:value-of select="string-join($tokenizedPath[position() gt 3], '/')"/>

XSL / XSLT - Adding a value-of as a style attribute for a DIV

I'm using SharePoint 2010 and the Content Query Web Part to output a list of dates from a SharePoint list. The display of this list is controlled by an XSL stylesheet called ItemStyle.xsl
I have made progress with the general appearance but would now like to add one of the fields it retrieves as a background/style attribute.
I believe the problem I am having relates to the xsl value-of select having a closing bracket at the end of the tag and therefore inadvertently closing my DIV. Can someone look at the code below and suggest alternative way of printing the CategoryColour within the opening DIV.
I also will occasional have "xmlns:ddwrt" inserted into the html where I would expect to at least see "style:background...."
Many Thanks
<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: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">
<!-- PrettyCal Template -->
<xsl:template name="PrettyCal" match="Row[#Style='PrettyCal']" mode="itemstyle">
<xsl:variable name="Start"><xsl:value-of select="#EventDate" /></xsl:variable>
<xsl:variable name="End"><xsl:value-of select="#EndDate" /></xsl:variable>
<xsl:variable name="AllDay"><xsl:value-of select="#AllDayEvent" /></xsl:variable>
<xsl:variable name="Location"><xsl:value-of select="#EventLocation" /></xsl:variable>
<xsl:variable name="CategoryColour"><xsl:value-of select="#EventCategoryColour" /></xsl:variable>
<div class="upcoming-events" style="background: {CategoryColour}" ><xsl:value-of select="$CategoryColour"/>
<h2 class="event-title">
<a>
<xsl:attribute name="onClick">
javascript:SP.UI.ModalDialog.showModalDialog({ url: '/services/marketing/Lists/College%20Calendar/DispForm.aspx?ID=<xsl:value-of select="#ID" />', title: 'Event Details' }); return false;
</xsl:attribute>
<xsl:value-of select="#Title" /></a></h2>
</div>
</xsl:template>
</xsl:stylesheet>
You have:
<div class="upcoming-events" style="background: {CategoryColour}" ><xsl:value-of select="$CategoryColour"/>
You actually wanted:
<div class="upcoming-events" style="background: {$CategoryColour}" ><xsl:value-of select="$CategoryColour"/>
Your missing a $ in front of the variable CategoryColour.

XSLT finding matching node by comparing element text to substring result

I am processing this XML:
<Brand>
<Brand_Name>BLENDERM</Brand_Name>
<Brand_Code>1103</Brand_Code>
<Groups>
<Group>
<Group_Code>657</Group_Code>
<Parent_Code>0</Parent_Code>
<Group_Level>1</Group_Level>
<Group_Name>Brand Default</Group_Name>
<Product>
<Pip_code>0032359</Pip_code>
<Status>In Use</Status>
Using this XSLT:
<xsl:template match="Product" mode="phase-3">
<xsl:value-of select="document('rx_catmapping.xml')/descendant::mapping[source=substring(ancestor::Brand/Brand_Name,1,1)]/target"/>
</xsl:template>
Here is a sample of rx_catmapping.xml:
<Lookup xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<mapping>
<source>a</source>
<target>788</target>
</mapping>
<mapping>
<source>B</source>
<target>789</target>
</mapping>
</Lookup>
So, I am processing the Product element, which is a descendant of Brand. The first letter of Brand/Brand_Name in this case is B, and I am trying to output the value 789 by looking it up in rx_catmapping.xml. This should be really simple but I am completely stumped! I have tried changing the first part of the XPath to refer to document('rx_catmapping.xml')/Lookup/mapping, or document('rx_catmapping.xml')//mapping. I have also tried changing the first half of the comparison to string(source), or to source/text(), but neither of these works either. (The reason for trying this was that using source='B', for example, did seem to work, so I wondered if I was trying to compare two incompatible data types.)
Thanks in advance for your help.
Define a key
<xsl:key name="k1" match="mapping" use="source"/>
then use
<xsl:variable name="map-doc" select="document('rx_catmapping.xml')"/>
and
<xsl:variable name="letter" select="substring(ancestor::Brand/Brand_Name,1,1)"/>
<xsl:for-each select="$map-doc">
<xsl:value-of select="key('k1', $letter)/target"/>
</xsl:for-each>
With XSLT 2.0 you can simplify that to
<xsl:value-of select="key('k1', substring(ancestor::Brand/Brand_Name,1,1), $map-doc)"/>
The problem is, I believe, that at the point where you do ancestor::Brand/Brand_Name, the context is the mapping element in the external file. This worked for me
<xsl:template match="/">
<xsl:apply-templates select=".//Product"/>
</xsl:template>
<xsl:template match="Product">
<xsl:variable name="x" select="substring(ancestor::Brand/Brand_Name,1,1)"/>
<xsl:value-of select="document('file:///c:/temp/rx_catmapping.xml')//mapping[source=$x]/target"/>
</xsl:template>

Outputting SharePoint Hyperlink Column as URL

I have some document URLs stored in a Sharepoint publishing column. When I output the info into a HTML page using:
<xsl:value-of select="#[ColumnName]" />
in ItemStyle.xml, I get [url], [document name] in the page. I would like to display this as a URL can anyone help with the XSL?
You could use:
<xsl:value-of select="substring-before(#[ColumnName],',')"/>
or whatever the separator is.
Thanks everyone, in the end I figured out the following based on a post at sguk
<xsl:variable name="Doc">
<xsl:call-template name="OuterTemplate.GetTitle">
<xsl:with-param name="Title" select="#DocumentLink1"/>
</xsl:call-template>
</xsl:variable>
with the following a tag code:
<a href="{substring-before($Doc,',')}">
<xsl:value-of select="substring-after($Doc,',')" />
</a>
or for an image:
<xsl:variable name="Image">
<xsl:call-template name="OuterTemplate.GetTitle">
<xsl:with-param name="Title" select="#img" />
</xsl:call-template>
</xsl:variable>
with the following img tag:
<img src="{substring-before($Image,',')}" alt="{substring-after($Image,',')}" />
I'm posting the solution back here as this proved ludicrously hard to figure out (probably my fault as I don't really 'get' XSL) but just in case anybody is looking for it, this code outputs images or links from the 'Hyperlink or Picture' column type in Sharepoint.
Another thing you can do is to take a list that shows URLs properly (like a Links list) and use SharePoint Designer to convert it to a DataView WebPart. In there will be the proper XSL for doing the conversion.
The easiest way to do this is with SharePoint designer:
click the field that shows "http://link, description"
a box with an > will appear, click it and you will get a "common xsl:value-of tasks" flyout.
It will have the field name and type, with the type set to "text".
Change the type to "hyperlink" and you will get a box allowing you to format the hyperlink. It will have all the necessary xsl already populated but you can input your own text or remove the link.
This hopefully helps. It shows "Project Site" when the hyperlink is entered and spaces when not.
<!--Project Site--><TD Class="{$IDAAO2UG}">
<xsl:variable name="Field" select="#Project_x0020_Site" />
<xsl:choose>
<xsl:when test="substring-before(#Project_x0020_Site, ', ')=''"><xsl:value-of select="substring-after(#Project_x0020_Site, ', ')" /></xsl:when>
<xsl:otherwise><A HREF="{substring-before(#Project_x0020_Site, ', ')}">
<xsl:choose>
<xsl:when test="substring-after(#Project_x0020_Site, ', ')=''"><xsl:value-of disable-output-escaping="no" select="substring-before(#Project_x0020_Site, ', ')" /></xsl:when>
<xsl:otherwise><xsl:value-of select="substring-after(#Project_x0020_Site, ', ')" /></xsl:otherwise>
</xsl:choose>
</A></xsl:otherwise>
</xsl:choose>
</TD>
In SharePoint 2013 you have to do things a bit differently because the #Url attribute is is no longer delimited with a comma. There is now a .desc sub property of #Url. Below is an example of how this works hopefully this saves someone else some time.
<xsl:template name="dvt_1.rowview">
<xsl:if test="string-length(#URL) > 0">
<div class="link-item item">
<a title="{#Comments}" target="_blank" href="{#URL}">
<xsl:value-of select="#URL.desc" />
</a>
</div>
</xsl:if>
</xsl:template>

Resources