i have the following xslt sheet:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:variable name="nhits" select="Answer[#nhits]"></xsl:variable>
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<div>
<xsl:call-template name="resultsnumbertemplate"/>
</div>
</xsl:template>
<xsl:template name="resultsnumbertemplate">
<xsl:value-of select="$nhits"/> matches found
</xsl:template>
</xsl:stylesheet>
And this is the xml that im trying to mix with the previous xslt:
<Answer xmlns="exa:com.exalead.search.v10" context="n%3Dsl-ocu%26q%3Dlavadoras" last="9" estimated="false" nmatches="219" nslices="0" nhits="219" start="0">
<time>
<Time interrupted="false" overall="32348" parse="0" spell="0" exec="1241" synthesis="15302" cats="14061" kwds="14061">
<sliceTimes>15272 </sliceTimes>
</Time>
</time>
</Answer>
Im using a xslcompiledtransform and that's working fine:
XslCompiledTransform transformer = new XslCompiledTransform();
transformer.Load(HttpContext.Current.Server.MapPath("xslt\\" + requestvariables["xslsheet"].ToString()));
transformer.Transform(xmlreader, null, writer);
My problems comes when im trying to put into a variable the "nhits" attribute value placed on the Answer element, but i'm not rendering anything using my xslt sheet.
Do you know what could be the cause?
Could be the xmlns attribute in my xml file?
Thanks in advance.
Best Regards.
Jose
Your immediate problem is that your XPath is wrong. Try
<xsl:variable name="nhits" select="/Answer/#nhits" />
However, I suggest a change to get rid of the variable altogether, you don't need it.
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output method="html" indent="yes"/>
<xsl:template match="Answer">
<div>
<xsl:value-of select="#nhits"/>
<xsl:text> matches found</xsl:text>
</div>
</xsl:template>
</xsl:stylesheet>
Your variable should be select="Answer/#nhits"
Your currect xpath of "Answer[#nhits]" tries to select Answer element that has an attribute named nhits..
Related
XML
<?xml version="1.0" encoding="UTF-8"?>
<!-- Edited by XMLSpy -->
<catalog>
<example>
:20:FT13261793408907
N23B:CRED
SA32A:130918USD111670,00
</example>
</catalog>
XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:for-each select="catalog">
<tr>
<td><xsl:value-of select="example"> </td>
</tr>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Current OUTPUT
:20:FT13261793408907 N23B:CRED SA32A:130918USD111670,00
Desired OUTPUT
:20:FT13261793408907
N23B:CRED
SA32A:130918USD111670,00
output must not be in a same line its must be as shown in the desired o/p
A template match should do it;
$ cat catalog.xsl
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="catalog">
<xsl:value-of select="example"/>
</xsl:template>
</xsl:stylesheet>
$ xsltproc catalog.xsl catalog.xml
:20:FT13261793408907
N23B:CRED
SA32A:130918USD111670,00
I have this XSLT to split a 25 MB XHTML file.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:apply-templates select="html/body"/>
</xsl:template>
<xsl:template match="body">
<xsl:for-each-group select="node()"
group-starting-with="*[position()=1 or #class='toc']">
<xsl:if test="count(current-group()[self::*]) > 0 ">
<xsl:variable name="filename" select="concat('/home/t',position(),'.xml' )"/>
<xsl:apply-templates/>
<xsl:result-document
indent="yes" method="xml" href="$filename}">
<html>
<xsl:copy-of select="/html/#*"/>
<xsl:for-each select="/html/node()">
<xsl:choose>
<xsl:when test="not(self::body)">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:copy-of select="current-group()"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</html>
</xsl:result-document>
</xsl:if>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
It currently works at splitting up the file when it finds a #toc. I need to alter this to be sensitive to size of the output file, as opposed to breaking at the #toc.
Desired end state: I want the result document to be about 500KB. I suppose position() might be the best way to regulate the split points?? I tried various string-length() approaches--I could not get one to work. Also, I think white space may be an issue.
By my calculations with these documents, splitting the file at a <p class="i0"> found at or near every 150th position increment should reliably give me the filesize I need.
I guess the best way to get there is to change this:
group-starting-with="*[position()=1 or #class='toc']"
So far I have not succeeded in anything I have changed it to. Thoughts?
UPDATE: I'm not ready to say this is answered, because someone may have a better idea. But right now I'm using group-starting-with="body/*[position()=1 or position() mod 350 = 0]" with some success. It is testing well.
UPDATE 2: The group-starting-with="body/*[position()=1 or position() mod 350 = 0]" is not working well. Problem is that it is the position within the for-each-loop, not the overall file.
The successful solution ended up being an xslt 3.0 accumulator.
As an alternative:
Dmitiri Novatchev solution for XSLT 1.0:
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="vResult">
<xsl:apply-templates/>
</xsl:variable>
Length of output is: <xsl:text/>
<xsl:value-of select="concat(string-length($vResult), '
')"/>
<xsl:if test="string-length($vResult) <= 1800">
<xsl:copy-of select="$vResult"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
when applied on this source.xml:
<nums>
<num>01</num>
<num>02</num>
<num>03</num>
<num>04</num>
<num>05</num>
<num>06</num>
<num>07</num>
<num>08</num>
<num>09</num>
<num>10</num>
</nums>
produces the wanted result:
Length of output is: 51
01
02
03
04
05
06
07
08
09
10
References
XSLT FAQ: WML and HDML - Measuring the size of the output file, in bytes
XSLT 3.0: Accumulator Function
Utilizing new capabilities of XML languages to verify integrity constraints
A Functional Tokenizer (Was: Re: Looping over a CSV in XSL)
XSL Techniques
FXSL:sumTree
How to bind xml file to asp.net dropdownlist using xmldatasource? If I do it like below, I see empty dropdownlist.
ASP.NET
<asp:DropDownList runat="server" ID="ddlDEMO" DataValueField="BILLAB" DataTextField="BILLAB" DataSourceID="xdsDemo">
</asp:DropDownList>
<asp:XmlDataSource ID="xdsDemo" runat="server" DataFile="~/XML/Bills.xml"
XPath="/Bills/Bill"></asp:XmlDataSource>
XML:
<?xml version="1.0" encoding="utf-8" ?>
<Bills>
<Bill>
<BILLID>1</BILLID>
<BILLAB>ONE</BILLAB>
</Bill>
</Bills>
It is working for attributes, not elements. This would have work if your XML looked like that:
<?xml version="1.0" encoding="utf-8" ?>
<Bills>
<Bill BILLID="1" BILLAB="ONE">
</Bill>
</Bills>
You can use transformation to fix it. Look here:
http://kanakaiah.wordpress.com/2008/05/06/using-xslt-files-with-the-new-xmldatasource-control/
Based on the solution in that link you should write xsl like that:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="Bills">
<Bills>
<xsl:apply-templates select="Bill"/>
</Bills>
</xsl:template>
<xsl:template match="Bill">
<Bill>
<xsl:attribute name="BILLID">
<xsl:value-of select="BILLID"/>
</xsl:attribute>
<xsl:attribute name="BILLAB">
<xsl:value-of select="BILLAB"/>
</xsl:attribute>
</BILL>
</xsl:template>
</xsl:stylesheet>
I would either create a class or a structure and serialize/deserialize from/to xml to my class/struct. Here is how you serialize your xml documents:
http://support.microsoft.com/kb/815813
After this I create a generic List of my class/struct and it is much easier to bind to anything and manipulate in general.
Good luck.
I am using the web.sitemap which is created using VS.net 2010 along with a XSLT to create a clean CSS-able menu.
I have modified the xslt from Cyotec to strip out the first node however I am so far unable to work out how to search within to display only the links depending on the role of the user.
The XSLT is as below:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:map="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" exclude-result-prefixes="map">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:template name="mapNode" match="/">
<ul id="main-menu">
<xsl:apply-templates select="*"/>
</ul>
</xsl:template>
<xsl:template match="/*/*">
<xsl:apply-templates select="*"/>
</xsl:template>
<xsl:template match="map:siteMapNode">
<xsl:if test="/siteMap/SiteMapNode[#roles != 'Admin']">
<li>
<a href="{substring(#url, 2)}" title="{#description}">
<xsl:value-of select="#title"/>
</a>
<xsl:if test="map:siteMapNode">
<xsl:call-template name="mapNode"/>
</xsl:if>
</li>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
The XML looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
<siteMapNode url="~/" title="" description="Anon" roles="*">
<siteMapNode url="~/anon.aspx" title="Anon" description="Anon" roles="*" />
<siteMapNode url="~/admin1.aspx" title="Admin1" description="Admin Only" roles="Admin"/>
<siteMapNode url="~/admin2.aspx" title="Admin2" description="Admin Only" roles="Admin">
<siteMapNode url="~/admin3.aspx" title="Admin3" description="Admin Only" roles="Admin"/>
</siteMapNode>
</siteMapNode>
</siteMap>
I am wanting to only output the urls titles and descriptions where roles != Admin
Everything works fine without the search.
Is anyone able to shed some light on the 'if' function, or suggest a better way of achieving this?
Thanks in advance
The problem with your current xsl:if condition....
<xsl:if test="/siteMap/SiteMapNode[#roles != 'Admin']">
.... is that the first forward slash means it is an absolute path, starting from the root element, so all the xsl:if is saying is whether there is any SiteMapNode, immediately under the siteMap element, that is not an Admin role. This means it will always be true in your case.
You really only want to check the role of the current element
<xsl:if test="#roles != 'Admin'">
However, there is a tidier way of doing this. Remove the xsl:if condition, and just have a separate template to match the admin role elements, and ignore them.
<xsl:template match="map:siteMapNode[#roles='Admin']"/>
Here is the full XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:map="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" exclude-result-prefixes="map">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:template name="mapNode" match="/">
<ul id="main-menu">
<xsl:apply-templates select="*"/>
</ul>
</xsl:template>
<xsl:template match="/*/*">
<xsl:apply-templates select="*"/>
</xsl:template>
<xsl:template match="map:siteMapNode[#roles='Admin']"/>
<xsl:template match="map:siteMapNode">
<li>
<a href="{substring(#url, 2)}" title="{#description}">
<xsl:value-of select="#title"/>
</a>
<xsl:if test="map:siteMapNode">
<xsl:call-template name="mapNode"/>
</xsl:if>
</li>
</xsl:template>
</xsl:stylesheet>
When applied to your sample XML, the following is output
<ul id="main-menu">
<li>
Anon
</li>
</ul>
Do note the template that matches the admin role element is more specific that the template that matches any SiteMapNode element and so the XSLT processor will give priority to this when matching.
I have a dateTime variable, and I want to convert it to a decimal value of epoch.
How can this be done?
I tried using:
seconds-from-duration($time, xs:dateTime('1970-01-01T00:00:00'))
but it just returns 0.
Please advice.
Thanks.
This transformation:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:sequence select="current-dateTime()"/>
<xsl:sequence select=
"( current-dateTime() - xs:dateTime('1970-01-01T00:00:00') )
div
xs:dayTimeDuration('PT1S')
"/>
</xsl:template>
</xsl:stylesheet>
when applied on any XML document (not used), produces the wanted result -- the current date-time and its Unix epoch (the number of seconds since 1/1/1970 ):
2010-08-12T06:26:54.273-07:00 1281594414.273
A pure xsl 1.0 lib example:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:date="https://github.com/ilyakharlamov/pure-xsl/date"
version="1.0">
<xsl:import href="https://raw.github.com/ilyakharlamov/pure-xsl/master/date.xsl"/>
<xsl:template match="/">
<xsl:variable name="time_as_timestamp" select="1365599995640"/>
<xsl:text>time_as_timestamp:</xsl:text><xsl:value-of select="$time_as_timestamp"/><xsl:text>
</xsl:text>
<xsl:variable name="time_as_xsdatetime">
<xsl:call-template name="date:date-time">
<xsl:with-param name="timestamp" select="$time_as_timestamp"/>
</xsl:call-template>
</xsl:variable>
<xsl:text>time_as_xsdatetime:</xsl:text><xsl:value-of select="$time_as_xsdatetime"/><xsl:text>
</xsl:text>
<xsl:text>converted back:</xsl:text>
<xsl:call-template name="date:timestamp">
<xsl:with-param name="date-time" select="$time_as_xsdatetime"/>
</xsl:call-template>
</xsl:template>
</xsl:stylesheet>
Output:
time_as_timestamp:1365599995640
time_as_xsdatetime:2013-04-10T13:19:55.640Z
converted back:1365599995640
As an xpath which does not use division but extracts from the duration:
for $i in (current-dateTime()-xs:dateTime('1970-01-01T00:00:00Z'))
return ((days-from-duration($i)*86400)+(hours-from-duration($i)*3600)+(minutes-from-duration($i)*60)+(seconds-from-duration($i)))