| Function | Signature and description |
|---|---|
| ms:string-compare | number ms:string-compare(string x, string y[, string language[, string options]]) Performs lexicographical string comparison. |
| ms:utc | string ms:utc(string time) Converts the prefixed date/time related values into Coordinated Universal Time and into a fixed (normalized) representation that can be sorted and compared lexicographically. |
| ms:namespace-uri | string ms:namespace-uri(string name) Resolves the prefix part of a qualified name into a namespace URI. |
| ms:local-name | string ms:local-name(string name) Returns the local name part of a qualified name by stripping out the namespace prefix. |
| ms:number | number ms:number(string value) Takes a string argument in XSD format and converts it into an XPath number. |
| ms:format-date | string ms:format-date(string datetime[, string format[, string locale]]) Converts standard XSD date formats to characters suitable for output. |
| ms:format-time | string ms:format-time(string datetime[, string format[, string locale]]) Converts standard XSD time formats to characters suitable for output. |
Here is a quick sketch on how to leverage XslCompiledTransform implementation of these functions to create custom XslContext class. The code above implments only ms:string-compare(), but other functions can be added in a similar way. Here is how you use it:
string xml = ""; XPathExpression expr = XPathExpression.Compile("ms:string-compare(value[1], value[2])"); MsXsltContext ctx = new MsXsltContext(); ctx.AddNamespace("ms", "urn:schemas-microsoft-com:xslt"); expr.SetContext(ctx); XmlDocument doc = new XmlDocument(); doc.LoadXml(xml); XPathNavigator nav = doc.DocumentElement.CreateNavigator(); Console.WriteLine(nav.Evaluate(expr)); ABCD EFGH
And here is sample MsXsltContext implementation:
using System;
using System.Xml.Xsl;
using System.Xml.XPath;
using System.Xml;
using System.Reflection;
using System.Xml.Xsl.Runtime;
using System.Globalization;
public class MsXsltContext : XsltContext
{
// Function to resolve references to my custom functions.
public override IXsltContextFunction ResolveFunction(string prefix,
string name, XPathResultType[] argTypes)
{
string namespaceUri = this.LookupNamespace(prefix);
if (namespaceUri == "urn:schemas-microsoft-com:xslt")
{
switch (name)
{
case "string-compare":
return new MsExtensionFunction(name, 2, 4,
new XPathResultType[] { XPathResultType.String,
XPathResultType.String, XPathResultType.String,
XPathResultType.String },
XPathResultType.Number);
}
}
return null;
}
public override IXsltContextVariable ResolveVariable(string prefix,
string name)
{
return null;
}
public override int CompareDocument(string baseUri, string nextBaseUri)
{
return 0;
}
public override bool PreserveWhitespace(XPathNavigator node)
{
return true;
}
public override bool Whitespace
{
get
{
return true;
}
}
}
public class MsExtensionFunction : IXsltContextFunction
{
private XPathResultType[] argTypes;
private XPathResultType returnType;
private string name;
private int minArgs;
private int maxArgs;
private MethodInfo method;
public int Minargs
{
get
{
return minArgs;
}
}
public int Maxargs
{
get
{
return maxArgs;
}
}
public XPathResultType[] ArgTypes
{
get
{
return argTypes;
}
}
public XPathResultType ReturnType
{
get
{
return returnType;
}
}
public MsExtensionFunction(string name, int minArgs,
int maxArgs, XPathResultType[] argTypes, XPathResultType returnType)
{
this.name = name;
this.minArgs = minArgs;
this.maxArgs = maxArgs;
this.argTypes = argTypes;
this.returnType = returnType;
}
public object Invoke(XsltContext xsltContext, object[] args,
XPathNavigator docContext)
{
switch (name)
{
case "string-compare":
if (method == null)
{
method = typeof(XsltFunctions).GetMethod("MSStringCompare");
}
object[] fullArgs = new object[maxArgs];
fullArgs[0] = ConvertToString(args[0]);
fullArgs[1] = ConvertToString(args[1]);
fullArgs[2] = args.Length > 2 ? ConvertToString(args[2]) : "";
fullArgs[3] = args.Length > 3 ? ConvertToString(args[3]) : "";
return method.Invoke(null, fullArgs);
}
return null;
}
private static string ConvertToString(object argument)
{
XPathNodeIterator it = argument as XPathNodeIterator;
if (it != null)
{
return IteratorToString(it);
}
else
{
return ToXPathString(argument);
}
}
private static string IteratorToString(XPathNodeIterator it)
{
if (it.MoveNext())
{
return it.Current.Value;
}
return string.Empty;
}
private static String ToXPathString(Object value)
{
string s = value as string;
if (s != null)
{
return s;
}
else if (value is double)
{
return ((double)value).ToString("R",
NumberFormatInfo.InvariantInfo);
}
else if (value is bool)
{
return (bool)value ? "true" : "false";
}
else
{
return Convert.ToString(value,
NumberFormatInfo.InvariantInfo);
}
}
}Don't forget to add a reference to the System.Data.SqlXml.dll.
Anyway, while digging around my phone filesystem I found a folder where J2ME applications are installed (/a/mobile/kjava/installed/) and there I found Gmail jar, image png file and other working files including RMS file. RMS stands for MIDP Record Management System (RMS) - a persistent storage for J2ME MIDlets. Seeing string "Login store" inside it I couldn't resist to scan it. What I found though was my Gmail username and password in clear text!
0000000FF0: FF FF FF FF FF FF FF FF │ FF FF FF FF FF FF FF FF 0000001000: 00 10 6F 6C 65 67 74 6B │ 40 67 6D 61 69 6C 2E 63 ►olegtk@gmail.c 0000001010: 6F 6D 00 0A 6D 79 70 61 │ 73 73 77 6F 72 64 FF FF om ◙mypassword 0000001020: FF FF FF FF FF FF FF FF │ FF FF FF FF FF FF FF FF
WTF???
Well, I can't affirm that Gmail for mobile application indeed stores user password in clear text, because I never got it fully working on my phone. Chances are they encrypt it after first successful login.
I need somebody to confirm this. If you've got Gmail for mobile application installed on your mobile, please take a look how your password is stored. I have no idea which mobile devices allow direct access to the file system, but at least it's very easy for Motorola phones. Just install P2K drivers and P2K Phone File Manager, run it and open /a/mobile/kjava/installed/ folder. Find Gmail's RMS file and inspect it.
PS. I did contact Google about this issue, but never got any response.
Why another XSLT task? Because existing ones suck. NAnt includes standard "style" task, but it uses obsolete slow and buggy XslTransform engine to perform transformations. MSBuild doesn't include XSLT task at all, while the Xslt task from the MSBuild Community Tasks Project is broken. Not no mention these tasks are barebone ones. If you need a better XSLT task for NAnt or MSBuild - nxslt task is for you.
Here is some highlights on this new nxslt task.
nxslt task is a free feature-rich task for NAnt and MSBuild that allows to perform XSL Transformations (XSLT) using .NET Framework 2.0 XSLT 1.0 implementation - XslCompiledTransform class. nxslt task supports plenty of advanced features:
nxslt and nxslt task are free tools under BSD license. Download here.
Btw, besides transforming XML documents nxslt task can also be used for pretty printing or resolving XIncludes. I'll post on this later.
Here is the deal. If you are working on a cool project, product, web site, service or whatever no matter open source or commercial one, which uses any XML technology in any way (hey, isn't anything matches this description nowadays?) you have a chance to win this $10K worth gray box from Microsoft called "Visual Studio 2005 Team Suite with MSDN Premium Subscription for one year". Everybody is eligible, no limitations or restrictions (well, microsofties and devs working for Al-Qaeda are obviously out).
To enter the contest you only need to describe your thing (project/product/web site/service/whatever) to me. Keep it simple. Don't forget to mention how any XML technology is involved. Just post it as a comment on this page. Or if you need pictures to describe it - write on your blog and post here a link. If your are not ready to disclose your stuff to the public eye, send me an email (and then if you win I promise not to unveil project details until you say me so).
It's me who will decide which entry is the coolest and so who is the winner. I'll probably consult my friends though.
Well, I'm XML and XSLT geek doing open source projects so I'm naturally biased toward such kind of things, but that means nothing. What I really want is to give it away to somebody who actually needs it and who is it going to use it to build something cool and preferably to benefit the community.
I'm accepting entries till December 24, 2006. Hurry up. Take a chance.