Wednesday 21 July 2010

FinalBuilder, XPath, WIX, XML namespaces etc.

A few weeks ago myself and another developer spent a morning scratching our heads trying to work out why we couldn't reference certain elements in Wix installation script using XPath through FinalBuilder. Every combination of element and attribute id's we tried produced an empty result set. The only thing that worked was when we referenced the attribute in question using the inbuilt XPath node() function. By using //node()/node() were were able to address the attributes local to the the first element. In the case of Wix this refers to the project element:

<wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<product id="{cea1706b-2804-4c85-b4eb-083b0394fccc}" name="LongArm" language="1033" version="2.187.0"></product>

Therefore using //node()/node() we are able to skip straight to the first child element of the first root element. From here we were able to use the attribute name of Id and Version to access the attributes we needed to generate an upgrade msi. I realised soon after that node() worked because it is namespace independent whereas our attempts at more fancy XPath queries required namespace resolution. Examples I found on the internet were all applied to xml files either devoid of namespaces or which used named namespaces. My first attempt at solving this issue was therefore to force a name on the namespace:

<wix xmlns:a="http://schemas.microsoft.com/wix/2006/wi">
<product id="{cea1706b-2804-4c85-b4eb-083b0394fccc}" name="LongArm" language="1033" version="2.187.0"></product>

This let me address the attributes I needed by using //a:Wix/a:Product

The first time I attempted to run this through the Wix compiler however I was greeted with a compilation error from visual studio. Candle.exe balked at the new and exciting namespace identifier.

Frustrated I then went back to FinalBuilder to see if there were any hints or tips on the configuration of the Edit XML File element. It was then I noticed the MSXML Parser tab in the Edit XML dialog screen:
I ticked the namespace prefix option and was amazed to see this work first time.

Tuesday 6 July 2010

RPN Calculator in Python.

RPN Calculator to solve first Praxis challenge.
http://programmingpraxis.com/2009/02/19/rpn-calculator/

Fairly happy with it, I don't feel right using the in operator to evaluate the token against a string though, it is a bit of a kludge. The first version of this program used a ValueError exception to parse an operator. Although in my heart of hearts I knew this was a bad thing to do it still felt somehow....cleaner.
import sys, operator

def main():
inplist = list(line.split() for line in sys.stdin.readlines())
functions = {'+':operator.add, '-':operator.sub, '*':operator.mul, '/':operator.truediv}

for expression in inplist:
out = list()
for token in expression:
if token[0] in '01234567890':
out.append(float(token))
else:
rhs = out.pop()
lhs = out.pop()
out.append(functions[token](lhs,rhs))
print out[0]

main()

Python input to lists..

Trying to stream a file into python and then convert each line by splitting on whitespace to a token list for parsing word by word.

I started out fairly verbose.

tokens= list()
lines= sys.stdin.readlines()
for line in lines:
tokens.append(line.split())


And ended up reducing it to a one liner.


inplist = list(i.split() for i in sys.stdin.readlines())