May 2004 - Posts
I have a XSLT that needs to reference a table of data, such as states. This data is very static, so it didn't seem to be worth the trouble to store this data in a table and pass it in as a node set. (See one my previous posts for an example of this.) I decided to embed this data as an XML “data island” in my XSLT and reference it via an XSLT variable. This is pretty standard stuff, but I couldn't get it to work.
I consulted my copy of XSLT and XPath On The Edge, by Jeni Tennison, and found that I was doing everything correctly. It still didn't work, so what was wrong?
.NET was the problem. In the 1.1 version of the framework, the transform method has a fourth argument, which is for a resolver. I've always passed null (or nothing) here, and everything worked well. When using the XSLT document() function, however, the resolver becomes important. Without a resolver, the document function is ignored. Examine the working code:
XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:st="http://www.mysite.com/States">
<xsl:output method="xml" indent="yes" />
<st:States>
<st:State Code="AL" Name="Alabama"/>
<st:State Code="MS" Name="Mississippi"/>
<st:State Code="TN" Name="Tennessee"/>
</st:States>
<xsl:variable name="VisaCodes" select="document('')//st:States/st:State"/>
</xsl:stylesheet>
.NET
myTransform.Transform(myXPathDoc, myArgumentList, OutputFile, new XmlUrlResolver());
I've been storing dates in SQL server, not as actual DateTime values, but as 100-nanosecond ticks using the BIGINT data-type. (Don't ask why; I have some really weird program requirements.) Up until recently, this caused no real issues, because .NET can easily handle the conversion. However, due to a scope change, I now have to create a Stored Procedure that does this conversion. So, how does one convert from .NET ticks to a SQL DateTime? Here ya go:
CREATE FUNCTION dbo.udfTicksToDateTime
(
@Ticks BIGINT
)
RETURNS DATETIME
AS
BEGIN
DECLARE @Days BIGINT
DECLARE @DaysBefore1753 BIGINT
DECLARE @TimeTicks BIGINT
DECLARE @Seconds BIGINT
SET @Days = @Ticks / CONVERT(BIGINT,864000000000)
SET @DaysBefore1753 = CONVERT(BIGINT,639905)
SET @TimeTicks = @Ticks % CONVERT(BIGINT,864000000000)
SET @Seconds = @TimeTicks / CONVERT(BIGINT,10000000)
RETURN DATEADD(s,@Seconds,DATEADD(d,@Days - @DaysBefore1753,CONVERT(DATETIME,'1/1/1753')))
END
I recently needed to pass some XML into my XSLT before performing a transform. Normally, this isn't very useful, because the XML gets converted into a string, not a node set. However, .NET provides a way around this problem. Because it took quite a while to discover the method, I thought I would note it here.
.NET Snippet
// create an XsltArgumentList to contain the node set
myArgumentList = new XsltArgumentList();
// load the nodes
NodeDoc = new XmlDocument();
NodeDoc.LoadXml(<Place XML here>);
// create a navigator, so that an iterator can be created
NodeNav = NodeDoc.CreateNavigator();
NodeItr = NodeNav.Select("/Parent/Child");
// populate argument list
myArgumentList.AddParam("NodeInfo", "", NodeItr);
// transform the XML directly to the file
myTransform.Transform(myXPathDoc, myArgumentList, OutputFile, new XmlUrlResolver());
XSLT Snippet
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:vc="http://www.me.com/Codes">
<xsl:param name="NodeInfo" select="/.."/>
<xsl:template match="/">
<xsl:for-each select="$NodeInfo">
...
</xsl:for-each>
</xsl:stylesheet>
Yes, another Security Summit. As always, I learned some new tricks, even while teaching the attendees. My favorite was while running a demo on one of my VPCs. The keyboard completely locked up, and nothing I did could correct this. (Having your PC lock up during a demo, in front of hundreds of people, is not a good feeling.) One of the attendees asked me to try pressing the left control key. I did, and the keyboard started working again. I will definitely remember this little trick.
As always, I want to thank a couple of the attendees for their participation. You know who you are! I really prefer leading a discussion group, rather than a simple lecture. Pratical experience beats rote knowlege every time!