Hello i have a question about XSL . I try to select all images in a directory with starts with filename 'img_'. at the moment my code is this:
<div class="flex-container">
<div class="flexslider">
<ul class="slides">
<xsl:for-each select="entry/fields/*[#type = 'image']">
<img>
<xsl:attribute name="src">
<xsl:value-of select="data/#image"/>
</xsl:attribute>
</img>
</li>
</xsl:for-each>
</ul>
</div>
</div>
what i tried is this
<div class="flex-container">
<div class="flexslider">
<ul class="slides">
<xsl:for-each select="entry/fields/*[#type = 'image' contains( ., 'img_' )]">
<li>
<img>
<xsl:attribute name="src">
<xsl:value-of select="data/#image"/>
</xsl:attribute>
</img>
</li>
</xsl:for-each>
</ul>
</div>
</div>
Can anyone help?
I hope its the right form to ask here .
Greetings
It seems, you just want to filter those images which are present, without breaking any link. So, you should use java extension to make it happen because XSLT only is not sufficient. Use something like:
<xsl:template match=file">
<xsl:variable name="file" select="resolve-uri(#name, base-uri(.))"
as="xs:string"/>
<xsl:if test="not(file:exists(file:new($file)))">
<xsl:value-of select="#name"/><xsl:message>file missing /
incorrect name</xsl:message>
</xsl:if>
</xsl:template>
I may get further information from http://www.altova.com/list/xsl-list/200906/msg1000300010.html
Related
Have this given piece of RDF/XML (can’t change it…):
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cel="http://namespaces.semaworx.org/content#" xmlns:dct="http://purl.org/dc/terms/" xmlns:i18n21="http://apache.org/cocoon/i18n/2.1">
<cel:page>
<dct:hasPart>
<cel:Element rdf:about="http://resources.semaworx.eu/content/element/start_navigation_home">
<cel:hasStructureI18n rdf:parseType="Literal"><i18n21:translate><i18n21:text key="start_navigation_home">Start</i18n21:text></i18n21:translate></cel:hasStructureI18n>
<i18n21:key>TheI18nKey</i18n21:key>
</cel:Element>
</dct:hasPart>
</cel:page>
</rdf:RDF>
Now I need to XSLT template-match specific "i18n21:key"-Elements based upon the URI in the "cel:Element"’s "rdf:about" attribute.
Best approach this far was something like
"cel:Element[contains(#rdf:about,'element/start_navigation_home')]/i18n21:key"
So this is an excerpt from the XSLT:
<xsl:template match="dct:hasPart" mode="layoutject_navigationMain_top">
<header id="navbar">
<nav>
<xsl:if test="$device != 'phone'">
<xsl:apply-templates select="cel:Element" mode="layoutject_languageSwitch"/>
<xsl:apply-templates select="cel:Element" mode="layoutject_navigationMain_inlineContent"/>
</xsl:if>
</nav>
</header>
</xsl:template>
<xsl:template match="cel:Element" mode="layoutject_navigationMain_inlineContent">
<ul id="main">
<xsl:apply-templates select="cel:Element[contains(#rdf:about,'urbanHOTBED/element/start_navigation_home')]/i18n21:key" mode="layoutject_navigationMain_singleItem" />
</ul>
</xsl:template>
<xsl:template match="cel:Element[contains(#rdf:about,'element/start_navigation_home')]/i18n21:key" mode="layoutject_navigationMain_singleItem">
<li class="ff">
<a href="/" title="back to Homepage" i18n21:attr="href title" class="nav_start">
<xsl:value-of select="cel:Element[contains(#rdf:about,'element/start_navigation_home')]/i18n21:key"/>
</a>
</li>
</xsl:template>
It’s only the last template, which won’t match as hoped for.
This far, I have tried being less specific in the "apply-templates" clause, as well as matching the full URI instead of using "contains".
I am trying to parse an XML and produce an HTML which could be used for printing.
The content of the elements in the XML are presented like cards and have information for the frontside as well as the backside. Eight cards would fit on a page.
To make life easier in the HTML/CSS world for positioning I would like to pre-arrange the XSLT output as follows:
For 16 elements in the input I would like to have first the frontside output of the first 8 elements, then the backside output of the first 8 elements in a different order that they match the corresponding frontside when two-sided printing is used, then the frontside output of the next 8 elements, etc.
The ordering for the backside is like this: first half in reverse order then the second half in reverse order. Ex. Backside card 4, 3, 2, 1, 8, 7, 6, 5.
Or for the following input(for the sake of simplicity I just use 4 cards per page for the example):
<cards>
<card>
<question>First for the front</question>
<answer>First to the back</answer>
</card>
<card>
<question>Second for the front</question>
<answer>Second to the back</answer>
</card>
<card>
<question>Third for the front</question>
<answer>Third to the back</answer>
</card>
<card>
<question>Fourth for the front</question>
<answer>Fourth to the back</answer>
</card>
<card>
<question>Fifth for the front</question>
<answer>Fifth to the back</answer>
</card>
</cards>
I would like to get the following output:
<html><body>
<div>
<div class="card1 front">First for the front</div>
<div class="card2 front">Second for the front</div>
<div class="card3 front">Third for the front</div>
<div class="card4 front">Fourth for the front</div>
</div>
<div>
<div class="card2 back">Second to the back</div>
<div class="card1 back">First to the back</div>
<div class="card4 back">Fourth to the back</div>
<div class="card3 back">Third to the back</div>
</div>
<div>
<div class="card1 front">Fifth for the front</div>
</div>
<div>
<div class="card1 back">Fifth to the back</div>
</div>
</body></html>
I have an idea to process the elements twice over next-match and modes but I have no idea how to combine it with the sorting/grouping I would like to apply.
I would be really thankful for a pointer into the right direction.
Lets make this generic - we want $rows rows of $cols cards each per page, and on the answer side each row needs to be printed in reverse order.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:param name="rows" select="2" />
<xsl:param name="cols" select="2" />
<xsl:variable name="pageSize" select="$rows * $cols" />
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates select="cards/card[position() mod $pageSize = 1]" />
</body>
</html>
</xsl:template>
<xsl:template match="card">
<!-- fronts -->
<div>
<xsl:call-template name="printRows">
<xsl:with-param name="element" select="1"/>
<xsl:with-param name="order" select="'ascending'" />
</xsl:call-template>
</div>
<!-- backs -->
<div>
<xsl:call-template name="printRows">
<xsl:with-param name="element" select="2"/>
<xsl:with-param name="order" select="'descending'" />
</xsl:call-template>
</div>
</xsl:template>
<xsl:template name="printRows">
<xsl:param name="element" />
<xsl:param name="order" />
<xsl:variable name="thePage"
select=". | following-sibling::card[position() < $pageSize]" />
<!-- split into rows -->
<xsl:for-each select="$thePage[position() mod $cols = 1]">
<xsl:variable name="theRow"
select=". | following-sibling::card[position() < $cols]" />
<!-- and process each row in appropriate order -->
<xsl:apply-templates select="$theRow/*[$element]">
<xsl:sort select="position()" order="{$order}" data-type="number" />
</xsl:apply-templates>
</xsl:for-each>
</xsl:template>
<xsl:template match="question">
<div class="card{(count(../preceding-sibling::card) mod $pageSize) + 1} front">
<xsl:value-of select="." />
</div>
</xsl:template>
<xsl:template match="answer">
<div class="card{(count(../preceding-sibling::card) mod $pageSize) + 1} back">
<xsl:value-of select="." />
</div>
</xsl:template>
</xsl:stylesheet>
This will work for any grid size, just set (or pass in) the number of rows and columns via the top two parameters. To calculate the class names I count preceding siblings so the numbers are based on the full set of card elements in their original document order - the position() function would give the sorted position, and only within the current row.
However, I think there may be a flaw in your logic for the output - in the final (short) row, the back of card five should be in the second column rather than the first, in order to print opposite its respective front. In general, if a "back" row has fewer than $cols cards in it then you need to left-pad it with empty divs to get everything to line up. One way to do that would be to modify the printRows template like this:
<!-- split into rows -->
<xsl:for-each select="$thePage[position() mod $cols = 1]">
<xsl:variable name="theRow"
select=". | following-sibling::card[position() < $cols]" />
<xsl:if test="$order = 'descending'">
<!--
special case for a short reverse row (i.e. the last row of the last page) - we need
to left-pad this row with empty columns to get the right positioning
-->
<xsl:call-template name="emptyDivs">
<xsl:with-param name="num" select="$cols - count($theRow)" />
</xsl:call-template>
</xsl:if>
<!-- and process each row in appropriate order -->
<xsl:apply-templates select="$theRow/*[$element]">
<xsl:sort select="position()" order="{$order}" data-type="number" />
</xsl:apply-templates>
</xsl:for-each>
Where the emptyDivs template is
<xsl:template name="emptyDivs">
<xsl:param name="num"/>
<xsl:if test="$num > 0">
<div class="padding back" />
<xsl:call-template name="emptyDivs">
<xsl:with-param name="num" select="$num - 1" />
</xsl:call-template>
</xsl:if>
</xsl:template>
This will produce the following output for a two row by two column page:
<html>
<body>
<div>
<div class="card1 front">First for the front</div>
<div class="card2 front">Second for the front</div>
<div class="card3 front">Third for the front</div>
<div class="card4 front">Fourth for the front</div>
</div>
<div>
<div class="card2 back">Second to the back</div>
<div class="card1 back">First to the back</div>
<div class="card4 back">Fourth to the back</div>
<div class="card3 back">Third to the back</div>
</div>
<div>
<div class="card1 front">Fifth for the front</div>
</div>
<div>
<div class="padding back"></div>
<div class="card1 back">Fifth to the back</div>
</div>
</body>
</html>
or the following for two rows by three columns:
<html>
<body>
<div>
<div class="card1 front">First for the front</div>
<div class="card2 front">Second for the front</div>
<div class="card3 front">Third for the front</div>
<div class="card4 front">Fourth for the front</div>
<div class="card5 front">Fifth for the front</div>
</div>
<div>
<div class="card3 back">Third to the back</div>
<div class="card2 back">Second to the back</div>
<div class="card1 back">First to the back</div>
<div class="padding back"></div>
<div class="card5 back">Fifth to the back</div>
<div class="card4 back">Fourth to the back</div>
</div>
</body>
</html>
This XSLT 1.0 transformation achieves the required structure:
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" encoding="UTF-8" indent="yes" />
<xsl:template match="/cards">
<html>
<body>
<xsl:for-each select="card[position() mod 4 = 1]">
<xsl:variable name="thisPage" select="
. | following-sibling::card[position() < 4]
" />
<div class="front">
<xsl:apply-templates select="$thisPage/question" />
</div>
<div class="back">
<xsl:apply-templates select="$thisPage/answer">
<xsl:sort select="substring('2143', position(), 1)" data-type="number" />
</xsl:apply-templates>
</div>
</xsl:for-each>
</body>
</html>
</xsl:template>
<xsl:template match="card/*">
<div class="card">
<xsl:value-of select="normalize-space()" />
</div>
</xsl:template>
</xsl:transform>
I take it that you don't really need the numbered CSS class names. Adding them makes things unnecessarily complicated.
If necessary you can achieve the same thing easily in your CSS stylesheet using nth-child.
.back .card:nth-child(1) {
/* this is card2 */
}
That being said, you could also have achieved the entire positioning on the back side independent of source order by combining position: absolute and nth-child in CSS. This way special ordering in XSLT would have been unnecessary.
I've the below XML
<?xml version="1.0" encoding="UTF-8"?>
<body>
<para><content-style font-style="bold">1/7 7.</content-style> This is First</para>
<para><content-style font-style="bold">1/8 8.</content-style> This is second<content-style format="superscript">6</content-style></para>
</body>
Here when i'm trying to apply template using my XSLT, though the above 2 paras are of same format, first is working and the second is not.
The expected output is as below.
<div class="para"><a name="P1-7"></a><span class="phrase">1/7</span> 7. This is First
</div>
<div class="para"><a name="P1-8"></a><span class="phrase">1/8</span> 8. This is second <span class="format-superscript">6</span>
</div>
and the current output that i get is
<div class="para"><a name="P1-7"></a><span class="phrase">1/7</span> 7. This is First
</div>
<para><span class="font-style-bold">1/8 8.</span> This is second<span class="format-superscript">6</span></para>
please let me know where am i going wrong and how to fix it.
Below is my XSL
<xsl:template match="para[content-style[matches(., '(\w+)/(\w+)')]][1]">
<div class="para">
<xsl:choose>
<xsl:when test="contains(substring-after(substring-after(./content-style/text(),'/'),'/'),' ')">
<xsl:analyze-string select="substring-before(.,' ')" regex="(\w+)/(\w+)/(\w+)">
<xsl:matching-substring>
<a name="{concat('P',regex-group(1),'-',regex-group(2),'-',regex-group(3))}"/>
<span class="phrase">
<xsl:value-of select="."/>
</span>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:analyze-string select="." regex="(\w+)/(\w+)">
<xsl:matching-substring>
<a name="{concat('P',regex-group(1),'-',regex-group(2))}"/>
<span class="phrase">
<xsl:value-of select="."/>
</span>
<xsl:text> </xsl:text>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:non-matching-substring>
</xsl:analyze-string>
<xsl:choose>
<xsl:when test="./#format">
<span class="format-{#format}">
<xsl:value-of select="substring-after(.,' ')"/>
</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="substring-after(.,' ')"/>
</span>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:analyze-string select="." regex="(\w+)/(\w+)/(\w+)">
<xsl:matching-substring>
<a name="{concat('P',regex-group(1),'-',regex-group(2),'-',regex-group(3))}"/>
<span class="phrase">
<xsl:value-of select="."/>
</span>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:analyze-string select="." regex="(\w+)/(\w+)">
<xsl:matching-substring>
<a name="{concat('P',regex-group(1),'-',regex-group(2))}"/>
<span class="phrase">
<xsl:value-of select="."/>
</span>
<xsl:text> </xsl:text>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:otherwise>
</xsl:choose>
</div>
</xsl:template>
<xsl:template match="content-style">
<xsl:apply-templates select="./node()[1][self::page]" mode="first"/>
<xsl:choose>
<xsl:when test="./#format">
<span class="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:apply-templates/>
</span>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Working DEmo
Thanks
If you don't want the first paragraph only, don't request it.
para[content-style[matches(., '(\w+)/(\w+)')]][1]
^
|
here
Remove the quantifier and insert it into another expression as indicated:
contains(substring-after(substring-after(./content-style[1]/text(),'/'),'/'),' ')
^
|
here
I need show with xslt information about an xml RSS feed.
The xml source is:
<description><![CDATA[<p>
<img style="margin: 10px;
float: left;" alt="Nuevo modelo general de negocio"
src="http://mysite.es/images/figure1.jpg" width="196" height="147" />
La compañía apuesta por un marcado giro en el modelo]]>
</description>
I´m using:
<xsl:value-of select="description" disable-output-escaping="yes"/>
But the rendering is not good because I need show a resize image, with size, for example 70x70.
I´ve tried with this but its wrong:
<xsl:value-of select="replace("description","images/","images/resized/images/")"
disable-output-escaping="yes"/>
The perfect solution for me would be to extract separated, both the src property and the text from the tag.
Regards,
María
If your xml always is like your example then you should be able to use something like this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
exclude-result-prefixes="xsl">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<div>
<xsl:apply-templates select="rss/channel"/>
</div>
</xsl:template>
<xsl:template match="rss/channel">
<ul>
<xsl:apply-templates select="item"/>
</ul>
</xsl:template>
<xsl:template match="item">
<xsl:variable name="item_link" select="link"/>
<xsl:variable name="item_title" select="substring-after(description, '/>')"/>
<xsl:variable name="item_image" select="substring-before(substring-after(description, 'src="'), '"')" />
<li>
<a href="{$item_link}">
<img alt="" src="{$item_image}" width="70" height="70" />
<xsl:value-of select="$item_title"/>
</a>
</li>
</xsl:template>
</xsl:stylesheet>
I have a form where a field is an image which is uploaded, which works fine. I now want to check to see if an image exists for that field and if not display a default no image
I have for now
<xsl:if test="fields/field_item_main_image/data/#original = ''"><span class="noimage"></span></xsl:if><xsl:copy-of select="fields/field_item_main_image/data" />
The span for no image simply provides a no image png file to be shown inplace of an image when none exists, but this is not working as the default image is not being shown, even though the field has no image assigned to it.
Looking at the source code the result is
<data></data>
What am I doing wrong?
ADDITIONAL INFO
I'd like to add more info but really not sure what you want me to add to help me... let me know what is needed and I will see if I can get that info for you to help me.
The relevant class style is
.noimage {display:block;width:100px;height:100px;background-image: url(../images/no-image-available.png);}
This is related to SobiPro a Joomla Compontent
Here is the form code
<div>
<xsl:for-each select="entry/fields/*">
<xsl:if test="( name() != 'save_button' ) and ( name() != 'cancel_button' )">
<xsl:variable name="fieldId">
<xsl:value-of select="data/*/#id" />
</xsl:variable>
<div id="{$fieldId}Container">
<xsl:attribute name="class">
<xsl:choose>
<xsl:when test="position() mod 2">spFormRowEven</xsl:when>
<xsl:otherwise>spFormRowOdd</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:if test="string-length( fee )">
<div class="spFormPaymentInfo">
<input name="{$fieldId}Payment" id="{$fieldId}Payment" value="" type="checkbox" class="SPPaymentBox" onclick="SP_ActivatePayment( this )"/>
<label for="{$fieldId}Payment">
<xsl:value-of select="fee_msg"></xsl:value-of><br/>
</label>
<div style="margin-left:20px;">
<xsl:value-of select="php:function( 'SobiPro::Txt', 'TP.PAYMENT_ADD' )" />
</div>
</div>
</xsl:if>
<div class="spFormRowLeft">
<label for="{$fieldId}">
<xsl:choose>
<xsl:when test="string-length( description )">
<xsl:variable name="desc">
<xsl:value-of select="description" />
</xsl:variable>
<xsl:variable name="label">
<xsl:value-of select="label" />
</xsl:variable>
<xsl:value-of select="php:function( 'SobiPro::Tooltip', $desc, $label )" disable-output-escaping="yes"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="label"/>
</xsl:otherwise>
</xsl:choose>
</label>
</div>
<div class="spFormRowRight">
<xsl:choose>
<xsl:when test="data/#escaped">
<xsl:value-of select="data" disable-output-escaping="yes"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="data/*" disable-output-escaping="yes"/>
</xsl:otherwise>
</xsl:choose>
<xsl:text> </xsl:text><xsl:value-of select="#suffix"/>
</div>
</div>
</xsl:if>
</xsl:for-each>
</div>
As part of the input one of my fields is an image field, it is that field I am wanting to check to see if a user has uploaded an image to that field, if they have then show that image, if not then show a default no image.
Does any of this help?
GW
If the default image for that field does not change, then I would do all of this on the client side.
Take a look at this answer to do that.