How would I prevent empty elements in XSL from nesting into each other?
I have a portion of my xsl that looks like this
<div class="social-share">
<div class="twitter-icon" data-url="{link}" data-text="{title}"></div>
<div class="facebook-icon" data-url="{link}" data-text="{title}"></div>
<div class="linkedin-icon" data-url="{link}" data-text="{title}"></div>
</div>
The javascript at the beginning of the file pulls in APIs related to these social media links, so they are intentionally empty. However, leaving these empty will result in the following structure which I do not want.
<div class="social-share">
<div class="twitter-icon" data-url="{link}" data-text="{title}">
<div class="facebook-icon" data-url="{link}" data-text="{title}">
<div class="linkedin-icon" data-url="{link}" data-text="{title}">
</div>
</div>
</div>
</div>
Full XSL
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output method="html" indent="yes"
doctype-system='http://www.w3.org/TR/html4/strict.dtd'
doctype-public='-//W3C//DTD HTML 4.01//EN'
/>
<xsl:template match="/rss">
<SCRIPT LANGUAGE="javascript" DEFER="true">
<xsl:comment>
<![CDATA[
jQuery(document).ready(function () {
(function (factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else {
factory(jQuery);
}
}(function ($) {
$.timeago = function (timestamp) {
if (timestamp instanceof Date) {
return inWords(timestamp);
} else if (typeof timestamp === "string") {
return inWords($.timeago.parse(timestamp));
} else if (typeof timestamp === "number") {
return inWords(new Date(timestamp));
} else {
return inWords($.timeago.datetime(timestamp));
}
};
var $t = $.timeago;
$.extend($.timeago, {
settings: {
refreshMillis: 60000,
allowPast: true,
allowFuture: false,
localeTitle: false,
cutoff: 0,
strings: {
prefixAgo: null,
prefixFromNow: null,
suffixAgo: "ago",
suffixFromNow: "from now",
inPast: 'any moment now',
seconds: "a few seconds",
minute: "about a minute",
minutes: "%d minutes",
hour: "about an hour",
hours: "about %d hours",
day: "a day",
days: "%d days",
month: "about a month",
months: "%d months",
year: "about a year",
years: "%d years",
wordSeparator: " ",
numbers: []
}
},
inWords: function (distanceMillis) {
if (!this.settings.allowPast && !this.settings.allowFuture) {
throw 'timeago allowPast and allowFuture settings can not both be set to false.';
}
var $l = this.settings.strings;
var prefix = $l.prefixAgo;
var suffix = $l.suffixAgo;
if (this.settings.allowFuture) {
if (distanceMillis < 0) {
prefix = $l.prefixFromNow;
suffix = $l.suffixFromNow;
}
}
if (!this.settings.allowPast && distanceMillis >= 0) {
return this.settings.strings.inPast;
}
var seconds = Math.abs(distanceMillis) / 1000;
var minutes = seconds / 60;
var hours = minutes / 60;
var days = hours / 24;
var years = days / 365;
function substitute(stringOrFunction, number) {
var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction;
var value = ($l.numbers && $l.numbers[number]) || number;
return string.replace(/%d/i, value);
}
var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) || seconds < 90 && substitute($l.minute, 1) || minutes < 45 && substitute($l.minutes, Math.round(minutes)) || minutes < 90 && substitute($l.hour, 1) || hours < 24 && substitute($l.hours, Math.round(hours)) || hours < 42 && substitute($l.day, 1) || days < 30 && substitute($l.days, Math.round(days)) || days < 45 && substitute($l.month, 1) || days < 365 && substitute($l.months, Math.round(days / 30)) || years < 1.5 && substitute($l.year, 1) || substitute($l.years, Math.round(years));
var separator = $l.wordSeparator || "";
if ($l.wordSeparator === undefined) {
separator = " ";
}
return $.trim([prefix, words, suffix].join(separator));
},
parse: function (iso8601) {
var s = $.trim(iso8601);
s = s.replace(/\.\d+/, "");
s = s.replace(/-/, "/").replace(/-/, "/");
s = s.replace(/T/, " ").replace(/Z/, " UTC");
s = s.replace(/([\+\-]\d\d)\:?(\d\d)/, " $1$2");
s = s.replace(/([\+\-]\d\d)$/, " $100");
return new Date(s);
},
datetime: function (elem) {
var iso8601 = $t.isTime(elem) ? $(elem).attr("datetime") : $(elem).attr("title");
return $t.parse(iso8601);
},
isTime: function (elem) {
return $(elem).get(0).tagName.toLowerCase() === "time";
}
});
var functions = {
init: function () {
var refresh_el = $.proxy(refresh, this);
refresh_el();
var $s = $t.settings;
if ($s.refreshMillis > 0) {
this._timeagoInterval = setInterval(refresh_el, $s.refreshMillis);
}
},
update: function (time) {
var parsedTime = $t.parse(time);
$(this).data('timeago', {
datetime: parsedTime
});
if ($t.settings.localeTitle) $(this).attr("title", parsedTime.toLocaleString());
refresh.apply(this);
},
updateFromDOM: function () {
$(this).data('timeago', {
datetime: $t.parse($t.isTime(this) ? $(this).attr("datetime") : $(this).attr("title"))
});
refresh.apply(this);
},
dispose: function () {
if (this._timeagoInterval) {
window.clearInterval(this._timeagoInterval);
this._timeagoInterval = null;
}
}
};
$.fn.timeago = function (action, options) {
var fn = action ? functions[action] : functions.init;
if (!fn) {
throw new Error("Unknown function name '" + action + "' for timeago");
}
this.each(function () {
fn.call(this, options);
});
return this;
};
function refresh() {
var data = prepareData(this);
var $s = $t.settings;
if (!isNaN(data.datetime)) {
if ($s.cutoff == 0 || Math.abs(distance(data.datetime)) < $s.cutoff) {
$(this).text(inWords(data.datetime));
}
}
return this;
}
function prepareData(element) {
element = $(element);
if (!element.data("timeago")) {
element.data("timeago", {
datetime: $t.datetime(element)
});
var text = $.trim(element.text());
if ($t.settings.localeTitle) {
element.attr("title", element.data('timeago').datetime.toLocaleString());
} else if (text.length > 0 && !($t.isTime(element) && element.attr("title"))) {
element.attr("title", text);
}
}
return element.data("timeago");
}
function inWords(date) {
return $t.inWords(distance(date));
}
function distance(date) {
return (new Date().getTime() - date.getTime());
}
document.createElement("abbr");
document.createElement("time");
}));
$('.headline-details').click(function () {
$(this).closest('.headline-item-small').find('.headline-hover-small').fadeToggle(300);
});
$('.close-headline').click(function () {
$(this).closest('.headline-item-small').find('.headline-hover-small').fadeToggle(300);
});
$('.twitter-icon').sharrre({
share: {
twitter: true
},
template: '<a class="box" href="#"><div class="share"><i class="fa fa-twitter"></i></div> <div class="count" href="#">{total}</div></a>',
enableHover: false,
enableTracking: true,
buttons: { twitter: {via: '_JulienH'}},
click: function(api, options){
api.simulateClick();
api.openPopup('twitter');
}
});
$('.facebook-icon').sharrre({
share: {
facebook: true
},
template: '<a class="box" href="#"><div class="share"><i class="fa fa-facebook"></i> </div><div class="count" href="#">{total}</div></a>',
enableHover: false,
enableTracking: true,
click: function(api, options){
api.simulateClick();
api.openPopup('facebook');
}
});
$('.linkedin-icon').sharrre({
share: {
pinterest: true
},
template: '<a class="box" href="#"><div class="share"><i class="fa fa-linkedin"></i> </div><div class="count" href="#">{total}</div></a>',
enableHover: false,
enableTracking: true,
click: function(api, options){
api.simulateClick();
api.openPopup('linkedin');
}
});
jQuery("abbr.timeago").timeago();
});
]]>
</xsl:comment>
</SCRIPT>
<div style="display:inline-block;">
<xsl:apply-templates select="channel" />
</div>
</xsl:template>
<xsl:template match="channel">
<div style="display:inline-block;">
<xsl:apply-templates select="item" />
</div>
</xsl:template>
<xsl:template match="item">
<!-- ... -->
<div class="headline-container">
<div class="headline-item-small">
<xsl:attribute name="style">background-image:url('<xsl:value-of select="enclosure/@url" />');</xsl:attribute>
<div>
<abbr class="timeago">
<xsl:attribute name="title"><xsl:value-of select="pubDate" disable-output-escaping="yes" /></xsl:attribute>
<xsl:comment><![CDATA[[if IE]><![if lte IE 8]><i class="fa fa-clock-o"></i><![endif]]]></xsl:comment>
</abbr>
<div class="headline-details">.<i class="fa fa-share">.</i></div>
</div>
<div class="headline-hover-small">
<i class="close-headline fa fa-times">.</i>
<p class="headline-p ellipsis multiline"><b>Teaser: </b><xsl:value-of select="description" disable-output-escaping="yes" /></p>
<div class="social-share">
<div class="twitter-icon" data-url="{link}" data-text="{title}">.</div>
<div class="facebook-icon" data-url="{link}" data-text="{title}">.</div>
<div class="linkedin-icon" data-url="{link}" data-text="{title}">.</div>
</div>
</div>
</div>
<a target="_self">
<xsl:attribute name="href"><xsl:value-of select="link" disable-output-escaping="yes" /></xsl:attribute>
<h3 class="headline-header"><xsl:value-of select="title" disable-output-escaping="yes" /></h3>
</a>
<xsl:comment><![CDATA[[if IE]><hr/><p style="font-size: 0.75em;margin: 0px;padding: 10px;text-align: justify;"><xsl:value-of select="description" disable-output-escaping="yes" /></p><![endif]]]></xsl:comment>
</div>
<!-- ... -->
</xsl:template>
</xsl:stylesheet>