XSLT counting position and group items accordingly - c#

I have some input XML which is
<collection>
<content>
<id>10</id>
<type>xx</type>
<title>xx</title>
<quicklink>xx</quicklink>
<teaser><p>xxx</p></teaser>
<root>
<thumb><img src="/xxx/xxx.jpg" /></thumb>
<link>http://www.foo.com</link>
</root>
<startDate></startDate>
<enddate></enddate>
<hyperlink>some text</hyperlink>
</content>
<content>
<id>10</id>
<type>xx</type>
<title>xx</title>
<quicklink>xx</quicklink>
<teaser><p>xxx</p></teaser>
<root>
<thumb><img src="/xxx/xxx.jpg" /></thumb>
<link>http://www.foo.com</link>
</root>
<startDate></startDate>
<enddate></enddate>
<hyperlink>some text</hyperlink>
</content>
<content>
<id>10</id>
<type>xx</type>
<title>xx</title>
<quicklink>xx</quicklink>
<teaser><p>xxx</p></teaser>
<root>
<thumb><img src="/xxx/xxx.jpg" /></thumb>
<link>http://www.foo.com</link>
</root>
<startDate></startDate>
<enddate></enddate>
<hyperlink>some text</hyperlink>
</content>
</collection>
XSLT written to format an unordered list as below
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<ul id="case-study-icons">
<xsl:for-each select="collection/content">
<li>
<a>
<xsl:attribute name="href">
<xsl:value-of select="Html/root/Link"/>
</xsl:attribute>
<xsl:attribute name="title">
<xsl:value-of select="title"/>
</xsl:attribute>
<img>
<xsl:attribute name="src">
<xsl:value-of select="Html/root/thumb/img/#src"/>
</xsl:attribute>
<xsl:attribute name="alt">
<xsl:value-of select="title"/>
</xsl:attribute>
<xsl:attribute name="width">92</xsl:attribute>
<xsl:attribute name="height">46</xsl:attribute>
</img>
</a>
</li>
</xsl:for-each>
</ul>
</xsl:template>
</xsl:stylesheet>
I would like to change this to have 3 image links inside one li and grounp every 3 item occurance into 3 image links groups wrapped withli`. So at the end of the transformation the HTML must look like below
<ul id="case-study-icons">
<li>
<img src="/foo.jpg" />
<img src="/foo.jpg" />
<img src="/foo.jpg" />
</li>
<li>
<img src="/foo.jpg" />
<img src="/foo.jpg" />
<img src="/foo.jpg" />
</li>
<li>
<img src="/foo.jpg" />
<img src="/foo.jpg" />
<img src="/foo.jpg" />
</li>
</ul>
I did try to do this myself using position() somehow my logic seems not working. Can someone please have a look? Many thanks in Advance..

Select every third Content element then start the li element, then within that select the three elements you need. It wasn't clear if your Content elements were siblings so I used following rather than following-sibling
<xsl:for-each select="(Collection/Content)[position() mod 3 = 1]">
<li>
<xsl:for-each select=".|following::Content[position() < 3]">
<a href="{Html/root/Link}" title="{Title}">
<img src="{Html/root/Thumb/img/#src}" alt="{Title}/>
</a>
</xsl:for-each>
</li>
</xsl:for-each>

Kindly David had pointed me at the right direction and I have managed to come to the correct transformation.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<ul id="case-study-icons">
<xsl:for-each select="(Collection/Content)[position() mod 3 = 1]">
<li style="width:100px; float:left;">
<xsl:for-each select=".|following-sibling::Content[position() < 3]">
<a>
<xsl:attribute name="href">
<xsl:value-of select="Html/root/Link"/>
</xsl:attribute>
<xsl:attribute name="title">
<xsl:value-of select="Title"/>
</xsl:attribute>
<img>
<xsl:attribute name="src">
<xsl:value-of select="Html/root/Thumb/img/#src"/>
</xsl:attribute>
<xsl:attribute name="alt">
<xsl:value-of select="Title"/>
</xsl:attribute>
<xsl:attribute name="width">92</xsl:attribute>
<xsl:attribute name="height">46</xsl:attribute>
</img>
</a>
</xsl:for-each>
</li>
</xsl:for-each>
</ul>
</xsl:template>
</xsl:stylesheet>

You might want to parameterise the number of items per group, rather than hard-code the 3. Additionally, it could be possibly be simplified, by firstly avoiding the need for nested xsl:for-each, and secondly by the use of Attribute Value Templates to write out attributes
Try this XSLT, for example
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="itemsperlist" select="3" />
<xsl:template match="/collection">
<ul id="case-study-icons">
<xsl:apply-templates select="content[(position() - 1) mod $itemsperlist = 0]" mode="first" />
</ul>
</xsl:template>
<xsl:template match="content" mode="first">
<li>
<xsl:apply-templates select=".|following-sibling::content[position() < $itemsperlist]" />
</li>
</xsl:template>
<xsl:template match="content">
<a href="{root/link}" title="{title}">
<img src="{root/thumb/img/#src}" alt="{title}" width="92" height="46" />
</a>
</xsl:template>
</xsl:stylesheet>
Note that this solution would work if you changed the 3 to a 1.

Related

IF statement in xslt for matching two id in BlogCategories

I Want to match the blogcategory ParentID With Parent id..
Here is my code:
<?xml version="1.0" encoding="utf-8"?>
<BlogCategories>
<BlogCategory ID="1" ParentID="0" Name="Travel" Active="1" seo_keywords="Travel Blogs" seo_description="Travel Blogs" ParentName=""/>
<BlogCategory ID="13" ParentID="1" Name="Destinations" Active="1" seo_keywords="Destinations" seo_description="Destinations" ParentName="Travel"/>
<Parent Id="1" ParentName="Travel"/>
<Parent Id="2" ParentName="HealthCare"/>
</BlogCategories>
This is my .xslt page:
<xsl:for-each select="Parent">
<div class="grid-row3">
<ul>
<a href="">
<xsl:value-of select="#ParentName"></xsl:value-of>
</a>
<xsl:for-each select="/BlogCategories/BlogCategory">
<xsl:if test="#ParentID=#ID">
<li>
<a href="">
<xsl:value-of select="#Name"></xsl:value-of>
</a>
</li>
</xsl:if>
</xsl:for-each>
</ul>
</div>
</xsl:for-each>
The problem is that the ParentID of block category( <BlogCategory ID="1" ParentID="0" Name="Travel" Active="1" seo_keywords="Travel Blogs" seo_description="Travel Blogs" ParentName=""/>) does not match with ID of parent( <Parent Id="1" ParentName="Travel"/>)
i.e. If i do manually <xsl:if test="#ParentID=1"> then it will work..but if i do the same things ..then the problem is here: <xsl:if test="#ParentID=#ID">
How do i match #ParentID=#ID
Try replacing:
<xsl:for-each select="/BlogCategories/BlogCategory">
with:
<xsl:for-each select="/BlogCategories/BlogCategory[#ParentID = current()/#Id]">
Then you won't need the xsl:if instruction at all.
The way you are trying to do this could only work if you had stored the Parent/#Idvalue in a variable before calling xsl:for-each - because the xsl:for-each instruction changes the context.
Another option (preferable, IMHO) is to use a key to resolve cross-references.
Note also that XML is case-sensitive: you cannot use #ID to select an attribute named Id.
Another way is to create a variable with Id parent :
<xsl:variable name="Id" select="#Id" />
and modify your condition with :
<xsl:if test="#ParentID=$Id">
the full code :
<xsl:for-each select="Parent">
<xsl:variable name="Id" select="#Id" />
<div class="grid-row3">
<ul>
<a href="">
<xsl:value-of select="#ParentName"></xsl:value-of>
</a>
<xsl:for-each select="/BlogCategories/BlogCategory">
<xsl:if test="#ParentID=$Id">
<li>
<a href="">
<xsl:value-of select="#Name"></xsl:value-of>
</a>
</li>
</xsl:if>
</xsl:for-each>
</ul>
</div>
</xsl:for-each>

replacement of multiple characters in a single element of xml using XSL

i am replacing &#10 with br tag to show new line while transforming xml using xsl. i want to replace blank spaces to its according code that may &nbsp or something else at the same time.sample code is below. please suggest for me what should i do.
while xml file may be as ------------
<?xml version="1.0" encoding="iso-8859-1"?><?xml-stylesheet type="text/xsl"
href="task.xsl"?><Nodes><sNode><Word><![CDATA[1
2.............3............4............5
3]]></Word></sNode></Nodes>
since blank spaces ommitted automatically so here ........ represents blank spaces.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<table>
<xsl:for-each select="Nodes/sNode">
<tr>
<td>
<xsl:call-template name="replace-string-with-element">
<xsl:with-param name="text" select="Word"/>
<xsl:with-param name="replace" select="'
'"/>
<xsl:with-param name="with" select="'br'"/>
</xsl:call-template>
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
<xsl:template name="replace-string-with-element">
<xsl:param name="text"/>
<xsl:param name="replace"/>
<xsl:param name="with"/>
<xsl:choose>
<xsl:when test="contains($text,$replace)">
<xsl:value-of select="substring-before($text,$replace)"/>
<xsl:element name="{$with}"/>
<xsl:call-template name="replace-string-with-element">
<xsl:with-param name="text" select="substring-after($text,$replace)"/>
<xsl:with-param name="replace" select="$replace"/>
<xsl:with-param name="with" select="$with"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
You could use xsl:character-map as follows:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="fn xs">
<xsl:character-map name="replaceChars">
<xsl:output-character character="
" string="br"/>
</xsl:character-map>
<xsl:output method="xml" version="1.0" encoding="UTF-8" use-character-maps="replaceChars" indent="yes"/>
<!-- Implement your templates -->
</xsl:stylesheet>
It is even possible to save all characters in a xsl:character-map in an external XSLT and use <xsl:import href="characterFile.xslt" />
To implement this in your stylesheet use the following XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:character-map name="replaceChars">
<xsl:output-character character="
" string="br"/>
</xsl:character-map>
<xsl:output method="html" use-character-maps="replaceChars"/>
<xsl:template match="/">
<html>
<body>
<table>
<xsl:for-each select="Nodes/sNode">
<tr>
<td>
<xsl:value-of select="Word" />
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>

How do I convert Richtext images from a standard WPF RichTextBox into HTML using XSLT?

How do I convert Richtext images from a standard WPF RichTextBox into HTML using XSLT?
Based on this answer, I have made the following XSLT file. So far, it converts Bold, Italic, Underlined, font family, font size, and font color. Now I still need it to convert images in the Richtext to HTML.
Image alignment does not have to be considered.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="msxsl x">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="x:Section[not(parent::x:Section)]">
<div>
<xsl:apply-templates select="node()"/>
</div>
</xsl:template>
<xsl:template match="x:Section">
<xsl:apply-templates select="node()"/>
</xsl:template>
<xsl:template match="x:Paragraph">
<p>
<xsl:apply-templates select="node()"/>
</p>
</xsl:template>
<xsl:template match="x:Run">
<xsl:variable name="style">
<xsl:if test="#FontStyle='Italic'">
<xsl:text>font-style:italic;</xsl:text>
</xsl:if>
<xsl:if test="#FontWeight='Bold'">
<xsl:text>font-weight:bold;</xsl:text>
</xsl:if>
<xsl:if test="contains(#TextDecorations, 'Underline')">
<xsl:text>text-decoration:underline;</xsl:text>
</xsl:if>
<xsl:if test="#FontSize != ''">
<xsl:text>font-size:</xsl:text>
<xsl:value-of select="#FontSize" />
<xsl:text>pt;</xsl:text>
</xsl:if>
<xsl:if test="#FontFamily != ''">
<xsl:text>font-family:</xsl:text>
<xsl:value-of select="#FontFamily" />
<xsl:text>;</xsl:text>
</xsl:if>
<xsl:if test="#Foreground != ''">
<xsl:text>color:#</xsl:text>
<xsl:value-of select="substring(#Foreground, 4)"/>
<xsl:text>;</xsl:text>
</xsl:if>
</xsl:variable>
<span>
<xsl:if test="normalize-space($style) != ''">
<xsl:attribute name="style">
<xsl:value-of select="normalize-space($style)"/>
</xsl:attribute>
</xsl:if>
<xsl:value-of select="text()"/>
</span>
</xsl:template>
</xsl:stylesheet>
You could add this template - include it above the final </xsl:stylesheet>
<xsl:template match="x:Image">
<img src="#Source" />
</xsl:template>

XML to treeview based on ParentId

I have an XML like this:
<table name="tblcats">
<row>
<Id>1741</Id>
<Industry>Oil & Gas - Integrated</Industry>
<ParentId>1691</ParentId>
</row>
<row>
<Id>1690</Id>
<Industry>Commodities</Industry>
<ParentId>1691</ParentId>
</row>
<row>
<Id>1691</Id>
<Industry>Capital Goods</Industry>
<ParentId>0</ParentId>
</row>
</table>
I want to create a Treeview from this XML so that table is parent node and then nodes ParentId 0 is second parent and then child nodes with Parent Id greater than 0
Like this:
+Table
+Capital Goods
Commodities
Oil & Gas - Integrated
How can I do this? Please suggest
Regards,
Asif Hameed
A fairly simplistic approach would be to use the standard ASP.NET controls XmlDataSource and TreeView and use an XSLT transform file to transform the XML you have into something that the TreeView control likes.
So, assuming you have the XML above in a file called cats.xml, the ASP.NET page markup would look like:
<asp:XmlDataSource ID="CatsXml" runat="server" DataFile="~/cats.xml" TransformFile="~/cats.xslt"></asp:XmlDataSource>
<asp:TreeView ID="CatsTree" runat="server" DataSourceID="CatsXml">
<DataBindings><asp:TreeNodeBinding TextField="name" ValueField="id" /></DataBindings>
</asp:TreeView>
and the XSLT file (cats.xslt) would be:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="table">
<table id="-1" name="Table">
<xsl:for-each select="/table/row[ParentId = 0]">
<industry>
<xsl:attribute name="id">
<xsl:value-of select="Id"/>
</xsl:attribute>
<xsl:attribute name="name">
<xsl:value-of select="Industry"/>
</xsl:attribute>
<xsl:call-template name="industry-template">
<xsl:with-param name="pId" select="Id" />
</xsl:call-template>
</industry>
</xsl:for-each>
</table>
</xsl:template>
<xsl:template name="industry-template">
<xsl:param name="pId" />
<xsl:for-each select="/table/row[ParentId = $pId]">
<industry>
<xsl:attribute name="id">
<xsl:value-of select="Id"/>
</xsl:attribute>
<xsl:attribute name="name">
<xsl:value-of select="Industry"/>
</xsl:attribute>
<xsl:call-template name="industry-template">
<xsl:with-param name="pId" select="Id" />
</xsl:call-template>
</industry>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Stuart.

xslt help - my transform is not rendering correctly

I'm trying to apply an xlst transformation using the following file. This is very basic, but I wanted to build off of this when I get it working correctly.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:template match="/">
<div>
<h2>Station Inventory</h2>
<hr/>
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="StationInventory">
<h5><xsl:value-of select="station-name" /></h5>
<xsl:apply-templates select="detector"/>
</xsl:template>
<xsl:template match="detector">
<span>
<xsl:value-of select="detector-name" />
</span>
<br/>
</xsl:template>
</xsl:stylesheet>
Here is some xml I'm using for the source.
<StationInventoryList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.dummy-tmdd-address">
<StationInventory>
<station-id>9940</station-id>
<station-name>Zone 9940-SEB</station-name>
<station-travel-direction>SEB</station-travel-direction>
<detector-list>
<detector>
<detector-id>2910</detector-id>
<detector-name>1999 West Smith Exit SEB</detector-name>
</detector>
<detector>
<detector-id>9205</detector-id>
<detector-name>CR-155 Exit SEB</detector-name>
</detector>
<detector>
<detector-id>9710</detector-id>
<detector-name>Pt of View SEB</detector-name>
</detector>
</detector-list>
</StationInventory>
</StationInventoryList>
Any ideas what I'm doing wrong? The simple intent here is to make a list of station, then make a list of detectors at a station. This is a small piece of the XML. It would have multiple StationInventory elements.
I'm using the data as the source for an asp:xml control and the xslt file as the transformsource.
var service = new InternalService();
var result = service.StationInventory();
invXml.DocumentContent = result;
invXml.TransformSource = "StationInventory.xslt";
invXml.DataBind();
Any tips are of course appreciated. Have a terrific weekend.
Cheers,
~ck
Replace by
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" xmlns:st="http://www.dummy-tmdd-address">
<xsl:template match="/">
<div>
<h2>Station Inventory</h2>
<hr/>
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="st:StationInventory">
<h5><xsl:value-of select="st:station-name" /></h5>
<ul>
<xsl:apply-templates select="st:detector-list/st:detector"/>
</ul>
</xsl:template>
<xsl:template match="st:detector">
<li>
<xsl:value-of select="st:detector-name" />
</li>
</xsl:template>
</xsl:stylesheet>
because detector is child of detector-list not station inventory and there is a namespace
There are two obvious problems:
All elements in the XML document are in the default namespace, but in the XSLT code they are referenced as belonging to "no namespace".
The element <StationInventory> doesn't have any <detector> children.
Solution:
In the XSLT stylesheet below the above two problems are corrected:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:d="http://www.dummy-tmdd-address">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<div>
<h2>Station Inventory</h2>
<hr/>
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="d:StationInventory">
<h5><xsl:value-of select="d:station-name" /></h5>
<xsl:apply-templates select="d:detector-list/d:detector"/>
</xsl:template>
<xsl:template match="d:detector">
<span>
<xsl:value-of select="d:detector-name" />
</span>
<br/>
</xsl:template>
</xsl:stylesheet>
The result now is a complete output, that most probably was wanted:
<div xmlns:d="http://www.dummy-tmdd-address">
<h2>Station Inventory</h2>
<hr />
<h5>Zone 9940-SEB</h5>
<span>1999 West Smith Exit SEB</span>
<br />
<span>CR-155 Exit SEB</span>
<br />
<span>Pt of View SEB</span>
<br />
</div>

Categories

Resources