inserting space in xslt - xslt

Hi I am using xslt to show the links on my webpart and i have added plus image next to my link.But I would like to add some space between them. I have added ,but this is not really working. Am i missing anything here? Please find my code below.
Thanks.
<xsl:choose>
<!-- do _self -->
<xsl:when test="contains(Link,'xxx')">
<a target="_self">
<xsl:attribute name="href">
<xsl:value-of select="URL"/>
</xsl:attribute>
<xsl:value-of select="Title"/>
</a>
</xsl:when>
<!-- use _blank (new browser window) -->
<xsl:otherwise>
<a target="_blank">
<xsl:attribute name="href">
<xsl:value-of select="URL"/>
</xsl:attribute>
<xsl:value-of select="Title"/>
</a>
</xsl:otherwise>
</xsl:choose>
<xsl:text> </xsl:text>
<xsl:choose>
<xsl:when test="Description !=' ' ">
<img class="imageclass" src="/images/plus.gif"></img>
</xsl:when>
</xsl:choose>

My understanding is that you want to produce HTML that would display white space in the browser.
If this is so, don't use spaces -- the brouser only displays one single space for a continuous sequence of spaces.
Use nonbreaking space:  
So, instead of:
<xsl:text> </xsl:text>
use:
<xsl:text>   </xsl:text>

The xsl:text instruction is the right tool for your requeriment. As example, this stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="#*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="a">
<xsl:call-template name="identity"/>
<xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
With this input:
<div>
link1
link1
link1
</div>
Output:
<div>link1 link1 link1 </div>

Related

xsl want to transform the following xml to html:

<!ELEMENT TITLE (CDATA | ELEMENTX )+ >
If I use the below then when
TITLE contains CDATA and
ELEMENTX contains CDATA I get duplicate text.
How should a template for this element TITLE be written?
<xsl:template match="TITLE">
<span>
<p><xsl:value-of select="."/></p>
<xsl:for-each select="*">
<xsl:choose>
<xsl:when test="local-name()='ELEMENT1'">
<xsl:apply-templates select="."/>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</span>
</xsl:template>
As per my understanding, it seems that you are stuck when mixed type of content allowed in DTD, and you are handling when CDATA appear and face issue if there is further child elements.
If you are suppose to push all child inside p then you can use <xsl:apply-templates/>
and handle further data in template.
If you only require for handle your code for CDATA updation then use
<p>
<xsl:if test="text()">
<xsl:value-of select="text()"/>
</xsl:if>
</p>
instead of
<p><xsl:value-of select="."/></p>
The following seems to do exactly what I need.
It puts out the Text from the parent element TITLE if any before any child element. Then it works on a child element if any and then puts out any text in the parent before the next child and so on.
<xsl:template match="TITLE">
<span>
<xsl:for-each select="* | ./text()">
<xsl:choose>
<xsl:when test="local-name()=''">
<xsl:value-of select="."/>
</xsl:when>
<xsl:when test="local-name()='ELEMENT1'">
<xsl:apply-templates select="."/>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</span>
</xsl:template>

xsl check if a root node contains any child nodes

Is there a way to determine if a a root level node contains any child nodes?
I have this code file that builds up a navigation menu for a drop-down menu, but for the root nodes that have no nodes below them I want to apply a different template to them:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:template match="/Home">
<xsl:apply-templates select="root" />
</xsl:template>
<xsl:template match="root">
<ul class="nav navbar-nav">
<xsl:apply-templates select="node">
<xsl:with-param name="level" select="0"/>
</xsl:apply-templates>
</ul>
</xsl:template>
<xsl:template match="node">
<xsl:param name="level" />
<xsl:choose>
<xsl:when test="$level=0">
<li>
<xsl:attribute name="class">
<xsl:if test="#breadcrumb = 1">active</xsl:if>
<xsl:if test="node">
<xsl:text> dropdown</xsl:text>
</xsl:if>
</xsl:attribute>
<xsl:choose>
<xsl:when test="#enabled = 1">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<xsl:attribute name="class">
<xsl:if test="node">
<xsl:text>dropdown-toggle</xsl:text>
</xsl:if>
</xsl:attribute>
<xsl:if test="node">
<xsl:attribute name="data-toggle">dropdown</xsl:attribute>
</xsl:if>
<xsl:value-of select="#text" />
<xsl:if test="node">
<b class="caret"></b>
</xsl:if>
</a>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="#text" />
</xsl:otherwise>
</xsl:choose>
<xsl:if test="node">
<ul class="dropdown-menu">
<xsl:apply-templates select="node">
<xsl:with-param name="level" select="$level + 1" />
</xsl:apply-templates>
</ul>
</xsl:if>
</li>
</xsl:when>
<xsl:otherwise>
<li>
<xsl:attribute name="class">
<xsl:if test="#breadcrumb = 1">active</xsl:if>
<xsl:if test="node">
<xsl:text> dropdown</xsl:text>
</xsl:if>
</xsl:attribute>
<xsl:choose>
<xsl:when test="#enabled = 1">
<a href="{#url}">
<xsl:value-of select="#text" />
</a>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="#text" />
</xsl:otherwise>
</xsl:choose>
</li>
<xsl:if test="node">
<!-- no extra level in default bootstrap -->
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Your question is not clear. If the root node does not have any child nodes, then the XML document is empty. Perhaps you meant the root element; there will be exactly one element like that and it's easy to see if it has any child nodes by using:
test="/*/node()"
in an xsl:if or xsl:when instruction.
Alternatively, you could use two templates - one matching a root element with child nodes:
<xsl:template match="/*[node()]">
and one for the other case:
<xsl:template match="/*[not(node())]">
You can use this XSLT-file:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" />
<xsl:template match="/*[count(descendant::*) = 0]">
No siblings
</xsl:template>
<xsl:template match="/*[count(descendant::*) > 0]">
Has siblings
</xsl:template>
</xsl:stylesheet>
With an input XML file with one or more siblings of the root element like this
<?xml version="1.0"?>
<root>
<a />
</root>
it will output "Has siblings".
And with an input file with an empty root tag like this
<?xml version="1.0"?>
<root>
</root>
it will output "No siblings".
If I understand the question correctly, try adding the template rule
<xsl:template match="root[not(*)]"/>

calling another template in Regex

I have the below piece of XML
<title>Conduct of external affairs <content-style font-style="italic">via</content-style> NGOs</title>
here when i'm trying to match with REGEX it is throwing me an error
The template i'm using is
<?xml version='1.0'?>
<xslt:stylesheet version="2.0" xmlns:xslt="http://www.w3.org/1999/XSL/Transform"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="Conjunction">(of)|(to)|(and)|(the)</xsl:param>
<xsl:template match="title">
<xsl:call-template name="changeUpperCase">
<xsl:with-param name="Text" select="text()"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="changeUpperCase">
<xsl:param name="Text"/>
<xsl:value-of select="for $EachToken in tokenize(lower-case($Text), ' ')
return
if(matches($EachToken, $Conjunction))
then
$EachToken
else
concat(upper-case(substring($EachToken, 1, 1)), substring($EachToken, 2))"/>
</xsl:template>
</xslt:stylesheet>
the error i'm getting is
XSLT 2.0 Debugging Error: Error: file:///C:/Users/u0138039/Desktop/Proview/HK/The%20Law%20of%20the%20Hong%20Kong%20Constitution/The%20Law%20of%20the%20Hong%20Kong%20Constitution/XSLT/Chapters.xsl:39: Wrong occurrence to match required sequence type - Details: - XPTY0004: The supplied sequence ('2' item(s)) has the wrong occurrence to match the sequence type xs:string ('zero or one')
i also declared a template for content-style, but i'm unable to know how to link it.
<xsl:template match="content-style">
<xsl:choose>
<xsl:when test="./#format">
<span class="{concat('format-',#format)}">
<xsl:apply-templates/>
</span>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="fontStyle">
<xsl:value-of select="concat('font-style-',#font-style)"/>
</xsl:variable>
<span class="{$fontStyle}">
<xsl:value-of select="."/>
<xsl:apply-templates select="para"/>
</span>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
but the above template is working if i use the below XML piece of code
<title>IS HONG KONG AN INTERNATIONAL PERSON?</title>
Case 2:
<title>PREPARATION FOR TRANSFER OF SOVEREIGNTY</title>
this should be converted to
Preperation for Transfer of Sovereignty
please let me know how i can solve this issue.
Thanks
I would suggest to use a consistent style of code with matching templates instead of called templates:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="Conjunction">(of)|(to)|(and)|(the)|(for)</xsl:param>
<xsl:template match="title">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="title/text()">
<xsl:value-of select="for $EachToken in tokenize(lower-case(.), ' ')
return
if(matches($EachToken, $Conjunction))
then
$EachToken
else
concat(upper-case(substring($EachToken, 1, 1)), substring($EachToken, 2))"/>
</xsl:template>
<xsl:template match="content-style">
<xsl:variable name="fontStyle" select="concat('font-style-',#font-style)"/>
<span class="{$fontStyle}">
<xsl:value-of select="."/>
<xsl:apply-templates select="para"/>
</span>
</xsl:template>
<xsl:template match="content-style[#format]">
<span class="{concat('format-',#format)}">
<xsl:apply-templates/>
</span>
</xsl:template>
</xsl:stylesheet>
That way the error simply vanishes as now there is a template for the text child nodes of your title elements processed by the apply-templates.
In your current code with-param name="Text" select="text()" you are passing a sequence of text child nodes to the template if the element has mixed content and that way the lower-case call has the wrong type of arguments.
The templates for content-style elements should now be applied as well but I am not sure they will do exactly what you want as you have not specified that in detail. Post a new question if there are still problems with that second part of your question.
Based on your comments I have revised the stylesheet to use analyze-string:
<?xml version='1.0'?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="Conjunction">^(of|to|and|the|for)$</xsl:param>
<xsl:template match="title">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="title/text()">
<xsl:analyze-string select="." regex="(\w)(\w*)">
<xsl:matching-substring>
<xsl:value-of
select="if (matches(., $Conjunction, 'i'))
then lower-case(.)
else concat(upper-case(regex-group(1)), lower-case(regex-group(2)))"/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
<xsl:template match="content-style">
<xsl:variable name="fontStyle" select="concat('font-style-',#font-style)"/>
<span class="{$fontStyle}">
<xsl:apply-templates/>
</span>
</xsl:template>
<xsl:template match="content-style[#format]">
<span class="{concat('format-',#format)}">
<xsl:apply-templates/>
</span>
</xsl:template>
</xsl:stylesheet>
Now Saxon 9.5 transforms
<root>
<title>HOW HIGH IS THE “HIGH DEGREE OF AUTONOMY’ OF HONG KONG?</title>
<title>PREPARATION FOR TRANSFER OF SOVEREIGNTY</title>
<title>Conduct of external affairs <content-style font-style="italic">via</content-style> NGOs</title>
</root>
into
<title>How High Is the “High Degree of Autonomy’ of Hong Kong?</title>
<title>Preparation for Transfer of Sovereignty</title>
<title>Conduct of External Affairs <span class="font-style-italic">via</span> Ngos</title>

Umbraco - Getting Textstring value

I'm trying to get the value of a text string of page, assign a url to it, and then display the result on a different page using xslt. I'm not sure how to get the value of the textstring.
Here is my macro:
<!-- Input the related links property alias here -->
<xsl:variable name="fieldName" select="/macro/fieldName"/>
<xsl:template match="/">
<xsl:if test="$fieldName != ''">
<!-- The fun starts here -->
<xsl:element name="a">
<xsl:if test="./new-window[. = 'True']">
<xsl:attribute name="target">_blank</xsl:attribute>
</xsl:if>
<xsl:attribute name="href">
<xsl:value-of select="/myUrl.aspx"/>
</xsl:attribute>
<xsl:value-of select="./#title"/>
</xsl:element>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Found it! select="$parent/*[name() = $fieldName]

How do I use XSLT to put a node set into an attribute value?

I have an xsl template that I want to call to put into an HTML node attribute:
<xsl:variable name="onClickJavaScript">
<xsl:call-template name="GetOnClickJavaScript" />
</xsl:variable>
<a id="123">
<xsl:attribute name="onclick">
<xsl:value-of select="$onClickJavaScript" />
</xsl:attribute>
</a>
My problem is that the call-template returns a node set and the attribute value wants to be a string. I can't seem to find any way to transform the node set into a string that works.
I have tried changing the value-of line to:
<xsl:value-of select="$onClickJavaScript/text()" />
But it complains that it needs to return a node set and that does not (which is what I was hoping, without the complaining part).
In the Visual Studio debugger I can see that $onClickJavaScript is a NodeSet with a single dimension and item. My string is buried in there, but not accessible :-(.
UPDATE...
When I call my template, it goes through a big case statement and calls another template. This other template has a <xsl:choose> and it goes down the following path in this case:
<xsl:when test="$isPrimary='true'">
<!-- Just provide the onclick event JavaScript -->
<xsl:value-of select='concat($launchMethod, "(this, &apos;", $id, "&apos;, &apos;", $nodeid, "&apos;, &apos;", $instanceid, "&apos;)")' />
</xsl:when>
With the information provided, your first sample should work, i.e.
<xsl:attribute name="onclick">
<xsl:value-of select="$onClickJavaScript" />
</xsl:attribute>
should insert an onclick attribute with the (string) value of $onClickJavaScript.
You can even simplify your XSLT by using an attribute value template:
<a id="123" onclick="{$onClickJavaScript}">...</a>
Or get rid of the variable and call the template inside the attribute node:
<xsl:attribute name="onclick">
<xsl:call-template name="GetOnClickJavaScript" />
</xsl:attribute>
My problem is that the call-template
returns a node set and the attribute
value wants to be a string. I can't
seem to find any way to transform the
node set into a string that works.
The problem is in the code you haven't shown.
In fact, I cannot reproduce this problem at all.
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="onClickJavaScript">
<xsl:call-template name="GetOnClickJavaScript" />
</xsl:variable>
<xsl:variable name="onClickJavaScript2">
<xsl:call-template name="GetOnClickJavaScript2" />
</xsl:variable>
<a id="123">
<xsl:attribute name="onclick">
<xsl:value-of select="$onClickJavaScript" />
</xsl:attribute>
</a>
<a id="123456">
<xsl:attribute name="onclick">
<xsl:value-of select="$onClickJavaScript" />
</xsl:attribute>
</a>
</xsl:template>
<xsl:template name="GetOnClickJavaScript">Hello</xsl:template>
<xsl:template name="GetOnClickJavaScript2">
<a>Hello</a>
</xsl:template>
</xsl:stylesheet>
when applied on any XML document (not used) produces its output without any errors:
<a id="123" onclick="Hello"/>
<a id="123456" onclick="Hello"/>
I'm not able to reproduce this either... here's what I tried, the onclick on the a gets "foo(this, '3', 'test')". What else is different? What is the result-tree-fragment that you're trying to call xsl:value-of on?
<xsl:template match="/">
<xsl:variable name="onclick-val">
<xsl:call-template name="foo" />
</xsl:variable>
<a>
<xsl:attribute name="onclick">
<xsl:value-of select="$onclick-val" />
</xsl:attribute>
</a>
</xsl:template>
<xsl:template name="foo">
<xsl:choose>
<xsl:when test="false()">
false
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="callme" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="callme">
<xsl:choose>
<xsl:when test="true()">
<xsl:value-of select='concat("foo", "(this, &apos;", "3", "&apos;, &apos;", "test", "&apos;)")' />
</xsl:when>
<xsl:otherwise>
false
</xsl:otherwise>
</xsl:choose>
</xsl:template>