Thursday, June 18, 2009

xslt function upper-case() in MSXML transformations

Today I wanted to use xslt to convert some incoming element to upper case so I can then use it in a look up routine. (mentioned in previous blog) Some simple Googling will most likely point to the XPath Version="2.0" function fn:upper-case(string).

However, using Microsoft's MSXML this function is not supported by their transformation engine. However, the fn:translate(...) function is supported so here is a simple way to convert all letters to uppercase.


Here is a sample conversion template:



<?xml version='1.0'?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<?xml version='1.0'?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="iso-8859-1" indent="yes" />
<xsl:variable name="lcletters">abcdefghijklmnopqrstuvwxyz</xsl:variable>
<xsl:variable name="ucletters">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>
<xsl:template match="convert">
<converted>
<toupper><xsl:value-of select="translate(lower,$lcletters,$ucletters)" /></toupper>
<tolower><xsl:value-of select="translate(upper,$ucletters,$lcletters)" /></tolower>
<touppermixed><xsl:value-of select="translate(mixed,$lcletters,$ucletters)" /></touppermixed>
</converted>
</xsl:template>
</xsl:stylesheet>



Here is a sample xml file:

<?xml version='1.0'?>
<convert>
<lower>convert to upper</lower>
<upper>CONVERT TO LOWER</upper>
<mixed>Convert This To All Upper</mixed>
</convert>


Here is a sample asp vbscript page:

<%@ Language=VBScript %>

<%Option Explicit%>

<%
Dim xslt
Dim xslProc
Dim xslDoc
Dim oXmlDoc
Set oXmlDoc = Server.CreateObject("Microsoft.XMLDOM")
oXmlDoc.load(Server.MapPath("convert.xml"))

set xslDoc = Server.CreateObject("MICROSOFT.FreeThreadedXMLDOM")
xslDoc.async = false
xslDoc.load(Server.MapPath("conversion.xsl"))

if xslDoc.parseError.errorCode = 0 Then
set xslt = Server.CreateObject("Msxml2.XSLTemplate")
xslt.stylesheet = xslDoc
set xslProc = xslt.createProcessor()
xslProc.input = oXmlDoc
xslProc.transform()
response.write "Conversion =" & Server.htmlencode(xslProc.output)
else
response.write "Error::" & xslDoc.parseError.reason
end if

%>



Give it a shot you should end up with something like:

Conversion =<?xml version="1.0" encoding="UTF-16"?> <converted> <toupper>CONVERT TO UPPER</toupper> <tolower>convert to lower</tolower> <touppermixed>CONVERT THIS TO ALL UPPER</touppermixed> </converted>

Lookup Tables in XSLT

Wow what a find today, I needed to do some data scrubbing while doing a transformation to guarantee some xml elements matched up to the enumerations in the target schema. I thought the easiest way would be to do a data lookup with the incoming value and just map it to the output necessary. This article is very well written and great example to follow.

http://www.ibm.com/developerworks/xml/library/x-xsltip.html

Monday, June 8, 2009

Transforming xml String in ASP/vbScript

When using the Microsoft XMLDOM in ASP there are plenty of tutorials like the ones at w3schools.com that describe loading and transforming an xml file on the server. In this case we were calling to a web service that returned xml in a string and wanted to send that string through an xslt transformation.

If you use the xmlDom.load(variableName) function like many of the examples you receive a error like:

The filename, directory name, or volume label syntax is incorrect


To correct this you need to use the xmlDom.loadXml(variableName)

Here is a sample ASP vbscript to show it working, notice the loadXml on line 29.



<%@ Language=VBScript %>

<%Option Explicit%>

<%
Dim xslt
Dim xslProc
Dim xslDoc
Dim xmlDoc
Dim sXslt
Dim sResponse
Dim sXmlString
Dim sErrMsg

sXslt = "myXslt.xsl"
sXmlString = "<?xml version=" & Chr(34) & "1.0" & Chr(34) & "?>" & vbCrLf
sXmlString = sXmlString & "<catalog>"& vbCrLf
sXmlString = sXmlString & "<cd><title>The Alter and The Door</title><artist>Casting Crowns</artist></cd>" & vbCrLf
sXmlString = sXmlString & "<cd><title>The Day Of</title><artist>David Wells</artist></cd></catalog>"

set xslDoc = Server.CreateObject("MICROSOFT.FreeThreadedXMLDOM")
xslDoc.async = false
xslDoc.load(Server.MapPath(sXslt))

if xslDoc.parseError.errorCode = 0 Then
set xmlDoc = Server.CreateObject("MICROSOFT.FreeThreadedXMLDOM")
xmlDoc.async = false
xmlDoc.loadXml(sXmlString)
if xmlDoc.parseError.errorCode = 0 Then
set xslt = Server.CreateObject("Msxml2.XSLTemplate")
xslt.stylesheet = xslDoc
set xslProc = xslt.createProcessor()
xslProc.addParameter "userid" , "1"
xslProc.addParameter "amount" , "100"
xslProc.addParameter "paymentDescriptor" , "Sample"
xslProc.addParameter "feeDescriptor" , "fee Sample"
xslProc.input = xmlDoc
xslProc.transform()
sResponse = xslProc.output
else
response.write "Internal Error " & xml2Doc.parseError.reason
end if
else
response.write "Internal Error : " & xslDoc.parseError.reason
end if

response.write "xslt = " & Server.HTMLEncode(xslDoc.xml) & "<hr>"
response.write "input xml String = " & Server.HTMLEncode(sXmlString) & "<hr>"
response.write "output xml = " & Server.HTMLEncode(sResponse)

%>


The xslt in this simplified example is:


<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="userid"/>
<xsl:param name="amount" />
<xsl:param name="paymentDescriptor"/>
<xsl:param name="feeDescriptor"/>
<xsl:output method="xml" version="1.0" encoding="iso-8859-1" indent="yes" />
<xsl:template match="/">
<transaction>
<userid><xsl:value-of select="$userid"/></userid>
<amount><xsl:value-of select="$amount"/></amount>
<payment_descriptor><xsl:value-of select="$paymentDescriptor"/></payment_descriptor>
<catalog>
<xsl:for-each select="catalog/cd">
<cd>
<title><xsl:value-of select="title"/></title>
<artist><xsl:value-of select="artist"/></artist>
<fee_descriptor><xsl:value-of select="$feeDescriptor"/></fee_descriptor>
</cd>
</xsl:for-each>
</catalog>
<status_code><xsl:value-of select="transaction/status_code"/></status_code>
<status_text><xsl:value-of select="transaction/status_text"/></status_text>
</transaction>
</xsl:template>
</xsl:stylesheet>

Wednesday, June 3, 2009

CVSNT to Linux CVS

Converting a cvsnt repository to native linux cvs was a simple copy of the repository except for the fact that cvsnt handles binary files differently.

Found this blog entry http://firefang.net/english/converting-cvsnt-repository-format-to-cvs-repository-format which described the difference in handling binary files. It resulted in running the commandline script below in the cvsroot directory after making sure all files/folders where writable by whoever is running the command. This is a one time operation, the back up scripts can easily be removed once the repository is verified.

Careful with the quotes this is to be a single line command. I had to work with the one from the blog above a bit, this worked notice the single quotes around expand:



find . -not -name "*,v.bak" -exec grep -q "kopt.*b" {} \; -not -exec grep -q "expand. *@b@;" {} \; -print0 | xargs -0 -i sh -c "echo conv {} ; cp {} {}.bak ; cat {}.bak | sed 2a\ 'expand @b@;' > {} "

Tuesday, June 2, 2009

ASP Respose.Redirect to JSP jsession

Well this starts my first ever blog, I've searched and used many such articles and find that it is high time to start giving back. Hope it's helpful to someone.

Today I found my self trying to link a legacy ASP web application to a J2EE web application. The idea was simple, take a request from the ASP page, formulate an XML request to the J2EE app for authentication, receive back the url from the J2EE app where to forward the user to complete the task. Pretty straight forward and simple ASP/VBScript until it came time to redirect the user.

Searching for how to Redirect in ASP one finds many articles on Response.Redirect ("url")

However, in my case the url looked something like:
http://my.servername.com:9999;jsessionid=skskdlrickdrfjfkwesf!20090624?myid=123456

When you push this through Response.Redirect it encodes the ";","="and "!" before the querystring thus you get something like:
http://my.servername.com:9999%3Bjsessionid%3Dskskdlrickdrfjfkwesf%2120090624?myid=123456

This doesn't play well on the J2EE server and hence you don't get to where you want to be.

Solution:

Take matters into your own hands with the HTTP Headers:

Response.Status = "302 Object moved"
Response.AddHeader "Location", Url
Response.End


The hint that was very helpful to me came from http://www.somacon.com/p145.php

Hope this helps.