.NET and XPath

July 1st, 2008

So I’m working on this XPath presentation for my team at work. I was trying to hack up a sample using some of the more interesting XPath functions, like string-join. PHP’s DOMXPath throws a fit when I use this function so I cracked open MSDN and saw that XPathNavigator in the 2.0 framework claims to support “the XQuery 1.0 and XPath 2.0 Data Model[s].” Nifty, huh? Especially since string-join is defined in those specs. (Note that this table claims it is available in XPath 1.0. Apparently nobody bothered to check the XPath 1.0 specification which does not mention it at all.)

PHP’s implementation must be broken then. Off I go and code a Winforms project that I can use to run my example. Right? Yeah, right…

For the sake of simplicity, I coded a small CLI program that will run an XPath query against an empty document:

using System;
using System.Xml;
using System.Xml.XPath;

public class XPathCLI {
    public static void Main(string[] args) {
        XmlDocument doc = new XmlDocument();

        XPathNavigator nav = doc.CreateNavigator();
        Console.WriteLine(nav.Evaluate(args[0]).ToString());
    }
}

Now let’s make sure it’s working:

$ ./XPathCLI.exe 'concat("hello ", "world")'
hello world

Looks good. Now let’s try the examples listed under string-join:

$ ./XPathCLI.exe "string-join({'Now', 'is', 'the', 'time', '...'}, \" \")"

Unhandled Exception: System.Xml.XPath.XPathException: invalid token: '{'
  at Mono.Xml.XPath.Tokenizer.ParseToken () [0x00000]
  at Mono.Xml.XPath.Tokenizer.advance () [0x00000]
  at Mono.Xml.XPath.XPathParser.yyparse (yyInput yyLex) [0x00000]
  at Mono.Xml.XPath.XPathParser.Compile (System.String xpath) [0x00000]

$ ./XPathCLI.exe “string-join({abra, cadabra}, \”\”)”

Unhandled Exception: System.Xml.XPath.XPathException: invalid token: ‘{’
  at Mono.Xml.XPath.Tokenizer.ParseToken () [0x00000]
  at Mono.Xml.XPath.Tokenizer.advance () [0x00000]
  at Mono.Xml.XPath.XPathParser.yyparse (yyInput yyLex) [0x00000]
  at Mono.Xml.XPath.XPathParser.Compile (System.String xpath) [0x00000]

$ ./XPathCLI.exe ’string-join((), “separator”)’

Unhandled Exception: System.Xml.XPath.XPathException: Error during parse of string-join((), “separator”) —> Mono.Xml.XPath.yyParser.yyException: irrecoverable syntax error
  at Mono.Xml.XPath.XPathParser.yyparse (yyInput yyLex) [0x00000]
  at Mono.Xml.XPath.XPathParser.Compile (System.String xpath) [0x00000] — End of inner exception stack trace —

  at Mono.Xml.XPath.XPathParser.Compile (System.String xpath) [0x00000]
  at System.Xml.XPath.XPathExpression.Compile (System.String xpath, IXmlNamespaceResolver nsmgr, IStaticXsltContext ctx) [0x00000]
  at System.Xml.XPath.XPathExpression.Compile (System.String xpath) [0x00000]
  at System.Xml.XPath.XPathNavigator.Compile (System.String xpath) [0x00000]
  at System.Xml.XPath.XPathNavigator.Evaluate (System.String xpath) [0x00000]
  at XPathCLI.Main (System.String[] args) [0x00000]

Ok, that didn’t go too well. Apparently Mono doesn’t like some of the syntax. Let’s use a node selecting expression instead:

$ ./XPathCLI.exe 'string-join(//something, "separator")'

Unhandled Exception: System.Xml.XPath.XPathException: function string-join not found
  at System.Xml.XPath.ExprFunctionCall.Evaluate (System.Xml.XPath.BaseIterator iter) [0x00000]
  at System.Xml.XPath.CompiledExpression.Evaluate (System.Xml.XPath.BaseIterator iter) [0x00000]

Uh… ok. Let’s start over on MS.NET. It must be a Mono bug, right?

>XPathCLI.exe "string-join({'Now', 'is' 'the', 'time', '...'}, \" \")"

Unhandled Exception: System.Xml.XPath.XPathException: 'string-join({'Now', 'is''the', 'time', '...'}, " ")' has an invalid token.
   at MS.Internal.Xml.XPath.XPathScanner.NextLex()
   at MS.Internal.Xml.XPath.XPathParser.ParseMethod(AstNode qyInput)
   at MS.Internal.Xml.XPath.XPathParser.ParsePrimaryExpr(AstNode qyInput)
   at MS.Internal.Xml.XPath.XPathParser.ParseFilterExpr(AstNode qyInput)
   at MS.Internal.Xml.XPath.XPathParser.ParsePathExpr(AstNode qyInput)
   at MS.Internal.Xml.XPath.XPathParser.ParseUnionExpr(AstNode qyInput)
   at MS.Internal.Xml.XPath.XPathParser.ParseUnaryExpr(AstNode qyInput)
   at MS.Internal.Xml.XPath.XPathParser.ParseMultiplicativeExpr(AstNode qyInput)
   at MS.Internal.Xml.XPath.XPathParser.ParseAdditiveExpr(AstNode qyInput)
   at MS.Internal.Xml.XPath.XPathParser.ParseRelationalExpr(AstNode qyInput)
   at MS.Internal.Xml.XPath.XPathParser.ParseEqualityExpr(AstNode qyInput)
   at MS.Internal.Xml.XPath.XPathParser.ParseAndExpr(AstNode qyInput)
   at MS.Internal.Xml.XPath.XPathParser.ParseOrExpr(AstNode qyInput)
   at MS.Internal.Xml.XPath.XPathParser.ParseXPathExpresion(String xpathExpresion)
   at System.Xml.XPath.XPathExpression.Compile(String xpath, IXmlNamespaceResolver nsResolver)
   at System.Xml.XPath.XPathNavigator.Evaluate(String xpath)
   at XPathCLI.Main(String[] args)

Let’s jump straight to the one that made it past Mono’s parser to crash in the evaluator:

>XPathCLI.exe "string-join(//something, \"separator\")"

Unhandled Exception: System.Xml.XPath.XPathException: Namespace Manager or XsltContext needed. This query has a prefix, variable, or user-defined function.
   at MS.Internal.Xml.XPath.CompiledXpathExpr.get_QueryTree()
   at System.Xml.XPath.XPathNavigator.Evaluate(XPathExpression expr, XPathNodeIterator context)
   at System.Xml.XPath.XPathNavigator.Evaluate(String xpath)
   at XPathCLI.Main(String[] args)

From this we can make a few conclusions:

  • Mono, MS.NET, and PHP do not support XPath 2.0. I cannot find any PHP documentation that claims a specific version of XPath support, but, as noted in the intro paragraph, MSDN claims XPath 2.0 support and MS.NET does not deliver. (Mono may be following the MS.NET implementation instead of the spec, so whether this is a Mono bug or not is debatable.)
  • Mono, MS.NET, and PHP do not support the {...} construct, which is present in the XPath 2.0 “Precedence Order” section but not actually defined elsewhere. This construct is not present at all in the XPath 1.0 specification. Whether this is a specification or implementation defect is left an open question.
  • Mono, MS.NET, and PHP do not implement the string-join function defined in at least XPath 2.0.

And from those conclusions we can draw a few more.

  • Nobody gives a whip about following the XPath specification.
  • The XPath specification is broken. Or confusing. Or (more likely) both.

The real question, then, is do people intentionally not implement the XPath 2.0 specification because they don’t want to, or because parts of it make no sense? It seems odd to me that an implementation would support concat and not string-join, especially since they are defined right next to each other.

In any case, if you’re not implementing all of it, don’t claim that you do. Incorrect documentation is worse than no documentation.

Linux Virtualization

June 26th, 2008

I’ve been using VirtualBox for some months now. It’s pretty slick and doesn’t get in my way too much. Just for the heck of it I’ve been experimenting with a few other similar systems: OpenVZ, vserver, KVM, and Xen. OpenVZ and KVM are the only two I’ve tinkered with long enough to at least have a clue what’s going on.

I was trying KVM at the suggestion of someone in #debian who seemed to like it a lot better than VirtualBox. After playing with KVM I’m not sure where this opinion came from. Just getting KVM and libvirtd to the point where I could actually run a VM took over a half hour. The virt-manager GUI looked nice but was buggy in some spots, and the lack of guest OS drivers meant that many things were a bit sluggish. On the plus side, networking was much easier to setup — but only sometimes. (If you add a network card *after* creating a VM you cannot choose which mode to run it in and are forced to use usermode NAT.) Another cool feature was emulation of a tablet pointing device in addition to a regular mouse device. This means that KVM doesn’t need any guest drivers for mouse integration, because it set the pointer position using the tablet.

At the end of the day, VirtualBox still wins for desktop virtualization. I’m still keeping KVM on the radar though.

You don’t have signal

June 9th, 2008

My DSL and phone service is due to be activated today. When I got up I had dialtone, which is a good sign. But a few days ago I had an interesting encounter that was just too humorous not to share.

On Thursday the DSL modem showed up but since I was spending the night at my parents’ house I didn’t tinker with it too much. Friday night I unpacked it and hooked it up. To my surprise it actually found DSL signal, but obviously failed on PPPoE authentication since I did not have my account information. I went out and got a cordless phone to see if I had dialtone, hoping to call AT&T customer service and get my DSL account name and password early. Of course I forgot that I needed to let the handset charge for a day. So I copied my order number and other info down and headed into the back room where I get good enough wireless signal from my neighbors to make Skype calls on my Pocket PC and called them up.

After giving her all the relevant numbers I explained the situation — that I had DSL signal and would like to try to connect. Hilarity ensued. This is a rough paraphrase of the conversation:

Me: My modem says I have DSL signal. Can I get my account info early?
AT&T: Hmm, I see here your line will be set up Monday, correct?
Me: Yes, that is the scheduled date.
AT&T: Do you have a dialtone yet?
Me: I have no way to check that yet. I don’t have a working phone.
AT&T: Well, if you don’t have dialtone then you cannot have a DSL signal.
Me: My modem says I have DSL signal. The DSL light is green and the modem diagnostics report that I have signal.
AT&T: What happened when you plugged the modem in?
Me: The DSL light flashed red for a few seconds, then it flashed green, and now it is solid green.
AT&T: Ok. It was flashing red — that means you don’t have signal.
Me: Well, it changed. It is not flashing red now, it is solid green.
AT&T: Yes, but it was flashing red when you plugged it in, and you don’t have dialtone, so you don’t have signal.
Me: I never said I don’t have dialtone… the modem is telling me that I have signal.
AT&T: That’s not possible, your line is not connected. You don’t have signal. That’s why the modem light was flashing red.

Around this point I gave up. Not so much out of frustration but I just could not believe what I was hearing. I could have understood refusal based on policy or simply that the person responsible for creating accounts had not yet created mine. But blatant denial of information presented to me by my equipment is ridiculous.

At least it makes for a good story…

‘Netless update

June 3rd, 2008

A few fun things have been happening, but I’ve been too busy to write about them. Now that I have time, I’ve just finished moving into my new house for the summer and won’t have Internet access until this Monday (or later if past experience on this topic is any indication).

Anyway, here is a rough list of developments since my last post.

  • I moved to a summer house nearer to my office (cutting my commute from one hour to about five minutes). But I already said that.
  • My computer is now sporting a new power supply, motherboard, GPU, and hard drive. I also upgraded my RAM from 1GB to 4GB. Compiz Fusion looks sweet on an 8800GT.
  • I’ve been in communication with two Mono people about the future of OpenVP. I don’t want to give too much away right now, but I can assure you that in the next couple of months OpenVP will be transforming into the visualization framework with the highest degree of ass-kickery around.

Banshee, meet OpenVP

April 30th, 2008

OpenVP, Banshee.

A week or two ago I was in #banshee chatting and posted a link to an album of some OpenVP screenshots. The developers were interested and asked me if I would try embedding OpenVP in Banshee. I have since submitted a patch that adds an interface that PlayerEngine classes can implement to become a visualization source, and also implements this interface on the GStreamer backend.

Once OpenVP is library-ized there will be a second patch adding an OpenVP extension, which will make Banshee do something like you see in the above screenshot. Probably not exactly as you see it there, since I’ll probably want to “take over” the Now Playing window and render there instead.

Basically what I’m saying is that all the ugly plumbing is done and right now it works. It just needs polish, and hopefully it’ll be ready when Banshee 1.0 is.

Bluetooth presence detection

April 14th, 2008

I recently found my USB Bluetooth adapter and have been tinkering with using it to talk to my Palm. I’ve successfully configured Linux to allow PPP connections over Bluetooth, so I can sync my Palm if I don’t have the cradle hooked up.

But a more interesting use for Bluetooth is presence detection. BlueProximity is a project that will establish a connection to a device and use it to trigger Gnome’s screensaver. When you leave the room the screensaver locks, and when you come back it unlocks. Nifty idea in theory, but it renders my Palm useless while I’m in the room — it displays a “Connecting” dialog that blocks use of anything else. While BlueProximity can be disabled with a few mouse clicks, why would I want to go through the hassle of disabling and enabling something that’s supposed to make my life easier? It’s far fewer steps to, say, hit a key combination to lock and enter my password to unlock.

But it’s not always necessary to make a connection. hcitool allows you to, for example, query device names by Bluetooth address. If it can get a response we assume that the device is in range. I’ve employed this technique in a script I’ve been maintaining over some years for myself. I trigger it from cron at certain times and it raises my volume to 90% and loops over a Spin Doctors song — a pretty effective alarm clock. What if I get up early and leave though? My neighbors probably wouldn’t appreciate hearing music that loud that early until I get back (however good the music may be). So last night I added a conditional that checks if my Palm is in range of my computer. It will only continue if it sees my Palm. And since I take my Palm everywhere, leaving my dorm room effectively disables my alarm clock. Neat.

I wonder if BlueProximity could be patched to allow picking between connection-based and name-discovery-based detection. This kind of tool has a lot of cool applications, such as setting Pidgin away when I leave and setting it available when I get back.

Better would be a “presence” D-Bus service that could be configured using a variety of presence-detection systems (such as checking for a Bluetooth device) and would fire an event when the user leaves or returns. Any interested application could be notified of user presence changes.

Chris’ Tasks, now with OpenID goodness

March 30th, 2008

My web-based task manager now supports OpenID as a login mechanism. Have at it.

She’s watching you

March 30th, 2008

The cake is a lie.

gnome-terminal cursor

March 28th, 2008

The latest release of gnome-terminal has removed the ability to disable the blinking cursor, which I had previously turned off. The only way to disable it is to disable blinking cursors in all text entry widgets. For some reason I prefer the cursor in text boxes to blink, but cannot stand a blinking terminal cursor. Every blink jars my mind and I lose focus, like someone’s looking at me waving his hands and yelling “hey!” every second.

Blink. Blink. Blink. Arrrgh.

Anyway, since the developers saw fit to remove this feature presumably under the GNOMEism of “keep things simple, users be damned,” I have coded a quick patch to permanently disable cursor blinking in gnome-terminal.

As frustrated as I am at what I think is a stupid decision, at least this is free software.

Chris’ Tasks

March 27th, 2008

I’ve started a web-based task manager to get some experience with Prototype. It’s very fast so far and is relatively easy to build upon.