XSLT - XML Value as CSS Class - css

I want to use data from XML to populate a class:
E.g.
<p class="<xsl:value-of select="a:Subject"/>">English</p>
Which would generate:
<p class="English">English</p>
IS this possible?

Yes, it is possible, use the below code with Attribute Value Template
<p class="{a:Subject}">English</p>

Yes via the <xsl:attribute>
Ex:
<xsl:template match="yourXPath">
<p>
<xsl:attribute name="class">
<xsl:value-of select="a:Subject"/>
</xsl:attribute>
</p>
</xsl:template>

Related

How to output an IMG tag from XML using XSLT

Here is my XML:
<?xml version="1.0" encoding="UTF-8"?>
<Collection>
<Content>
<ID>2779</ID>
<Type>Content</Type>
<Title>Article One</Title>
<QuickLink>/template.aspx?id=2779</QuickLink>
<Teaser />
<Html>
<root>
<NewsArticle>
<artTitle>The Comprehensive Breast Center: Quality Care on the Fast Track</artTitle>
<artThumb>
<img alt="Thumb Article One" src="/uploadedImages/Test/News/artOne.png?n=5954" />
</artThumb>
<artFull />
<releaseDate />
<contactName />
<contactPhone />
<contactEmail />
<artTeaser>The National Cancer Institute estimates that a woman in the United States has a 1 in 8 chance of developing invasive breast cancer</artTeaser>
<artText>
<p>The Comprehensive Breast Center: Quality Care on
the Fast Track</p>
<p>
How do I display the IMG tag from my XML above to an HTML document using XSLT
Something like this should do the trick:
<xsl:template match="/">
<xsl:for-each select="Collection/Content">
<xsl:copy-of select="Html/root/NewsArticle/artThumb/node()"/>
</xsl:for-each>
</xsl:template>
I should note that this assumes you're getting this from an Ektron collection -- assumption made based on your tagging of this question. This will display the image from each content block in the collection. If you want just the image from the first content block of the collection, you could remove the for-each and instead use something like this:
<xsl:template match="/">
<xsl:copy-of select="Collection/Content/Html/root/NewsArticle/artThumb/node()"/>
</xsl:template>
Also, it works either way, but i removed the slash from the front of the select on the for-each. Seemed redundant since the code is in a template that already matches on "/".
UPDATE
Some of that can be done in the workarea -- it allows you to set the css class, though I'm not sure if you can set the title attribute of an image. Here's how you could do that via XSLT. In this case, you can't copy the node whole-sale:
<xsl:template match="/">
<xsl:for-each select="Collection/Content">
<xsl:variable name="imageSrc" select="Html/root/NewsArticle/artThumb/img/#src" />
<xsl:variable name="imageId">
<xsl:text>NewsArticle_</xsl:text>
<xsl:value-of select="ID" />
<xsl:text>_image</xsl:text>
</xsl:variable>
<xsl:variable name="contentTitle" select="Html/root/NewsArticle/artTitle" />
<img id="{ $imageId }" class="myCssClass" title="{ $contentTitle }" alt="{ $contentTitle }" src="{ $imageSrc }" />
</xsl:for-each>
</xsl:template>
(Updated again - appears i misread your comment. Thanks, #MathiasMüller!)
When assigning ids to elements like this, I prefer to use a little more than just the content id. In this case, by using "NewsArticle_{Content ID}image", I allow for a container div to use an id "NewsArticle{Content Id}" if it is needed in the future without colliding with the image ids.
How do i assign a title and an alt from artTitle and also a class and id?
Building upon the answer given by #BrianOliver, this is how you output an img element whose "title" attribute reflects the content of artTitle from your input XML - the same for ID.
I assume that by "an alt from artTitle" you mean that the text content of img/#alt should also come from the artTitle element.
<xsl:template match="/">
<xsl:for-each select="Collection/Content">
<xsl:variable name="imageSrc" select="Html/root/NewsArticle/artThumb/img/#src" />
<!--xsl:variable name="imageAlt" select="Html/root/NewsArticle/artThumb/img/#alt" /-->
<xsl:variable name="imageId" select="ID"/>
<xsl:variable name="imageTitle" select="Html/root/NewsArticle/artTitle"/>
<img id="{$imageId}" class="myCssClass" title="{$imageTitle}" alt="{ $imageTitle}" src="{$imageSrc}"/>
</xsl:for-each>
</xsl:template>
However, I am not sure where the class attribute should come from.

XSL transformatiotion to XForms from simple XML file and applying CSS

I am transforming some simple XML document into XForms and I am trying to add some style to the final result. I am using the XSLTForms implementation and I am pointing to a local CSS file (Twitter's bootstrap). So the XML file looks like that:
<structure>
<part class="Container" id="container">
<part class="Button" id="b1"/>
</part>
</structure>
<style>
<property part-name="b1" name="label">Submit</property>
</style>
My XSLT that transforms these parts to XForms document:
<xsl:key name="buttonLabels" match="property[#name='label']" use="#part-name"/>
<xsl:template match="part[#class='Button']"><!-- [key('buttonActions', #id)]-->
<xsl:element name="xf:trigger">
<xsl:attribute name="id">
<xsl:value-of select="#id | #size | #style"/>
</xsl:attribute>
<xsl:element name="xf:label">
<xsl:value-of select="key('buttonLabels', #id)"/>
</xsl:element>
</xsl:element>
</xsl:template>
<xsl:template match="part[#class='Container']">
<xsl:element name="div">
<xsl:attribute name="class">container</xsl:attribute>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
Now, this produces: (which is fine for what I need currently)
<div class="container">
<xf:trigger id="b1">
<xf:label>Submit</xf:label>
</xf:trigger>
</div>
But I'd like to add some style rules to this <xf:trigger>. The thing is that when it gets transformed into html elements, the structure is
|_span
|_span
|_button
|_span (for the label)
So I am not sure how to make the XSLT transformation, so that it inserts let's say class="btn-danger" attribute into the <button> tag.
In other words, I need to get something like that in the final Html: (currently I get it, but without the class="btn-danger" in the button tag)
<span id="b1">
<span>
<button type="button" class="btn-danger">
<span id="xsltforms-mainform-label-2_6_2_4_3_" class="xforms-label">Submit</span>
</button>
</span>
</span>
Besides, I tried with adding an <xsl:attribute name="class">btn-danger</xsl:attribute> in the template for the xf:trigger, but that inserts the attribute at the first span element.
Any ideas? Thanks in advance!
UPDATE:
The XSLT responsible for transforming the xforms:trigger element to html elements can be found on this link - http://bpaste.net/show/c42CtcIcjbsI6GFGWK2q/
But I don't want to edit the XSLTForms implementation, but rather find a workaround, so that I can specify the style of my buttons from my XML file.
For example:
<structure>
<part class="Container" id="container">
<part class="Button" id="b1"/>
</part>
</structure>
<style>
<property part-name="b1" name="label">Submit</property>
<property part-name="b1" name="style">btn-danger</property>
</style>
So here, I am matching the part-name and saying that I want the button with id="b1" to have css style rules for btn-danger for example. But if I have another button and there is no style rule for it, it should have default appearance. Hope that's clear.
You cannot add a class attribute directly to the button element generated by XSLTForms.
But instead of it, you can define a CSS rule that applies to it this way:
#myclass button {
color: red;
}
and use the class in the trigger:
<xf:trigger class="myclass >
The same for every XForms control. Just take a look to the browser inspector to see the generated controls.

processing css stylesheet with xml document

I am new to XML (a couple of days now...)and everything is going good, however, I can't seem to get the xml processed with css style
here is my perl...
#!/usr/bin/perl -w
use strict;
use warnings;
use diagnostics;
use Text::CSV_XS;
my $csv = Text::CSV_XS->new ({ binary => 1, auto_diag => 1 });
my $ifile="elementarray.csv";
my $ofile="elementarray.xml";
open my $fh, "<", $ifile or die $ifile.": $!";
open my $out, "> ".$ofile or die "Cannot write ".$ofile.": $!";
print $out <<EOT;
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="elementarray.xsl"?>
<?xml-stylesheet href="elementarray.css" title="Default style"?>
<EMAILCOMMENTS>
EOT
# First record contains list of fieldnames
#my $fields = $csv->getline($fh);
#print #$fields;
while (my $row = $csv->getline($fh)) {
last unless $row && #$row;
# Encode "<" characters as "<" and "&" as "&" in all fields
foreach (#$row) {
s/&/&/g;
s/</</g;
}
# Create hash of fields using hash slice
my %row;
#row{"Subject","Body","From: (Name)","From: (Address)","To: (Name)","To:(Address)","Date","Time"} = #$row;
print $out <<EOT;
<EMAIL>
<HEADER>
<ORIGNAME>$row{"From: (Name)"}</ORIGNAME>
<ORIGADDRESS>$row{"From: (Address)"}</ORIGADDRESS>
<DESTNAME>$row{"To: (Name)"}</DESTNAME>
<DESTADDRESS>$row{"To: (Address)"}</DESTADDRESS>
<SUBJECT>$row{"Subject"}</SUBJECT>
</HEADER>
<BODY>$row{"Body"}</BODY>
<DATE id="date">$row{"Date"}</DATE>
<TIME id="time">$row{"Time"}</TIME>
</EMAIL>
EOT
}
print $out "</EMAILCOMMENTS>\n";
$csv->eof or $csv->error_diag;
close $fh or die $ifile.": $!";
close $out or die $ofile.": $!";
Here is my xsl...
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes" method="html"/>
<xsl:template match="/"><!-- a 'pattern', / matches the root node -->
<html>
<head>
<title>E-mail</title>
</head>
<body>
<xsl:apply-templates/><!-- an instruction -->
</body>
</html>
</xsl:template>
<xsl:template match="HEADER">
<span STYLE="color:red; font-weight:bold; font-style:italic">
<xsl:value-of select="SUBJECT"/>
</span>
From: <xsl:call-template name="formatEmail">
<xsl:with-param name="address" select="ORIGADDRESS"/>
</xsl:call-template>
To: <xsl:call-template name="formatEmail">
<xsl:with-param name="address" select="DESTADDRESS"/>
</xsl:call-template>
</xsl:template>
<xsl:template match="EMAIL">
<xsl:apply-templates select="HEADER"/>
<pre>
<xsl:value-of select="BODY"/>
</pre>
<div>
<span>
<xsl:attribute name="id"><xsl:value-of select="date"/></xsl:attribute>
<!-- --><xsl:value-of select="DATE"/><!-- --></span>
<span>
<xsl:attribute name="id"><xsl:value-of select="time"/></xsl:attribute>
<!-- --><xsl:value-of select="TIME"/><!-- --></span>
</div>
<br />
</xsl:template>
<xsl:template name="formatEmail">
<xsl:param name="address"/>
<a>
<xsl:attribute name="href"><xsl:value-of select="concat('mailto:',$address)"/></xsl:attribute>
<xsl:value-of select="$address"/>
</a>
</xsl:template>
</xsl:stylesheet>
here is my xml (1 record)...
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="elementarray.xsl"?>
<?xml-stylesheet href="elementarray.css" title="Default style"?>
<EMAILCOMMENTS>
<EMAIL>
<HEADER>
<ORIGNAME>William Holt</ORIGNAME>
<ORIGADDRESS><x#gmail.com></ORIGADDRESS>
<DESTNAME>X</DESTNAME>
<DESTADDRESS>bill#elementarray.com</DESTADDRESS>
<SUBJECT>welcome to the neighborhood</SUBJECT>
</HEADER>
<BODY>just thought i'd say hello</BODY>
<DATE id="date">07/18/2013</DATE>
<TIME id="time">11:53</TIME>
</EMAIL>
</EMAILCOMMENTS>
and here is css ( style for just to see if it is working, and it isn't :( )...
DATE{background-color:red;}
TIME{background-color:green;}
#date{background-color:yellow;}
#time{background-color:blue;}
BODY{background-color:grey;}
Sorry for the length of the post but I think you need all these files...
Although you can indeed style XML with CSS, using the xml-stylesheet processing instruction you have included in your XML, you can't transform it with XSLT at the same time. That is to say you should only really have one stylesheet processing instruction in your XML. Either you simply style your XML with CSS (which is not really a common thing to do), or your transform it to HTML with XSLT and style the HTML output with CSS.
In the latter case, remove the <?xml-stylesheet href="elementarray.css"?> instruction from your XML document, and instead output a reference to the CSS document in your first template.
<xsl:template match="/">
<html>
<head>
<title>E-mail</title>
<link href="elementarray.css" type="text/css" rel="stylesheet" />
</head>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
Now, in your CSS, I see you already have selectors for the date and time ids, so you need to ensure the relevant elements in your HTML have these ids.
At the moment, you are doing this in your XSLT
<span>
<xsl:attribute name="id"><xsl:value-of select="date"/></xsl:attribute>
<!-- --><xsl:value-of select="DATE"/><!-- --></span>
<span>
But this is setting the id attribute to have the value of the date element in your XML, but such an element does not exist! I think you meaning to use the literal string here. Now, you could do this...
<xsl:attribute name="id"><xsl:value-of select="'date'"/></xsl:attribute>
But this is verbose. You can just do this:
<xsl:attribute name="id">date</xsl:attribute>
But better still, just write it out as an attribute in the normal way:
<span id="date">
<xsl:value-of select="DATE"/>
</span>
And similarly for 'time'. This should ensure the two span tags get styled using your CSS in the HTML you output.

How do I call a specific CSS class name in an xsl: when test= statement, so the test proves true?

I have a rotator component that acts one way on the homepage, another way on every other page. I want to strip out one more attribute when it is on the homepage within the CSS div class "tabimage."
<div class="tabimage">
<xsl:apply-templates select="RotatorComponent[#Name = 'ProfileRotator']"/>
Here is the complete code. The first test is what I am working on, the when and otherwise works fine. Since posting this question, I have come to the conclusion that I need to not just select the CSS, but somehow differentiate if it is a parent or not of the rotator component, right?
<xsl:template match="RotatorComponent[#Name='ProfileRotator']/Navigation/Page" mode="Rotator">
<xsl:param name="visible" />
<xsl:if test="parent::node/#RotatorComponent = 'tabimage'">
<div class="assessimg"><img src="images/{#Thumbnail}" alt="{#ProfileName}" width="189" height="213"/></div>
</xsl:if>
<xsl:choose>
<xsl:when test="not(/HomePage)">
<xsl:if test="#Thumbnail">
<a href="{#URL}">
<img src="images/{#Thumbnail}" alt="{#Title}"/>
</a>
</xsl:if>
<p class="quote"><xsl:value-of select="#Quote"/></p>
</xsl:when>
<xsl:otherwise>
<div class="module">
<div class="assessbox">
<div class="studentprofileboxinner">
<xsl:variable name="profileVar" select="/*/Page[#Name = 'Profile']"/>
<div class="assessimg"><img src="images/{#Thumbnail}" alt="{#ProfileName}" width="189" height="113"/></div
<div class="assesscopy">
<h3><xsl:value-of select="#ProfileType"/> Story</h3>
<p><xsl:value-of select="#Abstract"/></p>
<!--assessimage-->
<!--assessimage-->
</div>
</div>
</div>
</div><!-- module -->
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Well, first of all, it depends on what node is the current one - so it depends on what statements are called before the choose element.
If the current node is the div one, then the test should work; if it isn't, then it won't work.

how to get child nodes in xsl

here my code-
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="ArrayOfLinkEntity" name="bindLink">
<ul>
<xsl:for-each select="LinkEntity[ParentLinkId=0]">
<li>
<xsl:variable name="linkId" select="LinkId"/>
<xsl:variable name="child" select="count(/ArrayOfLinkEntity/LinkEntity[ParentLinkId=$linkId])"/>
<xsl:value-of select="$child"/>
<xsl:choose>
<xsl:when test="($child > 0)">
<a href="#" data-flexmenu="flexmenu1" onclick="javascript:setPageLinkId({$linkId});">
<xsl:value-of select="LinkTitle"/>
<img src="../images/down.gif" border="0"/>
</a>
</xsl:when>
<xsl:otherwise >
<a href="#" onclick="javascript:setPageLinkId({$linkId});">
<xsl:value-of select="LinkTitle"/>
</a>
</xsl:otherwise>
</xsl:choose>
</li>
</xsl:for-each>
</ul>
</xsl:template>
</xsl:stylesheet>
but I am getting $child=0 always.but there exists children.
my xml structure-
<ArrayOfLinkEntity xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<LinkEntity>
<EntityId>00000000-0000-0000-0000-000000000000</EntityId>
<LinkId>1</LinkId>
<SequenceNo>1</SequenceNo>
<ParentLinkId>0</ParentLinkId>
<LinkTitle>Home</LinkTitle>
<SubLink />
</LinkEntity> ...
</ArrayOfLinkEntity>
What should I do? Please suggest.
but I am getting $child=0 always.but
there exists children.
If by "children" you mean a LinkEntity with ParentLinkId child that is equal to the LinkId of the current node, the result you get is correct.
The only LinkEntity has an LinkId 1, but there are no LinkEntity elements in the provided XML document whose ParentLinkId is 1.
You need to show a complete (but the shortest possible) XML document on which your code exhibits this issue. Without being able to repro the problem, no one can give you a logical advice.
From your following code:
<xsl:variable name="linkId" select="LinkId"/>
<xsl:variable name="child" select="count(/ArrayOfLinkEntity/LinkEntity[ParentLinkId=$linkId])"/>
This occurs within a for-each loop where the only nodes being looped over are LinkEntity's with ParentLinkId = 0. But from your source XML, the value of LinkId = 1, and in your variable assignment for $child, you are selecting on LinkEntity's with ParentLinkId = 1, which don't exist in your source XML data.
If I misunderstood something please let me know, but from what I can see that may be the problem.

Resources