Some correct XPath expressions don't work as expected

I'm doing some XML transform on a file generated by WiX after harvesting registry data. For those who are unfamiliar with WiX, just consider I'm trying to do XML transfer on a XML file, no matter where it is coming from. The issue I'm experiencing is: when I use XPath like

match="node()[name() = 'File'][not(@KeyPath)]"

then the matching works fine and it finds all those File nodes that are missing the KeyPath attribute in it, however, if I use another expression of XPath like

match="//File[not(@KeyPath)]"

then it doesn't find any match.

In general I cannot use the standard XPaths with /, //, ., .., however, a piece below with an XPath example in it works well

<xsl:template match="node()[name() = 'File']
                               [contains(@Source, 'First.dll') or 
                                contains(@Source, 'Second.dll')]
                               [not(@Assembly)]">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
            <xsl:attribute name="Assembly">.net</xsl:attribute>
            <xsl:attribute name="KeyPath">yes</xsl:attribute>
        </xsl:copy>
    </xsl:template>

but something like /bookstore/book[@lang='en'] would not work. Perhaps, I'm missing some descriptions at the beginning of my XSL file to enable recognition of Xpaths like this.

1 answer

  • answered 2017-01-11 14:26 Tim C

    This is because the nodes in the XML file are almost certainly in a namespace

    <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
    

    Your expression //File[not(@KeyPath)] is looking for a File element that is is no namespace. You need to account for the namespace in your XSLT

    So, bind a prefix to it on the xsl:stylesheet like so...

    <xsl:stylesheet version="1.0"
                    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                    xmlns:wix="http://schemas.microsoft.com/wix/2006/wi" />
    

    Then your match expression becomes this..

    <xsl:template match="//wix:File[not(@KeyPath)]" />
    

    In fact, the // is not necessary here in a match. This will work too

    <xsl:template match="wix:File[not(@KeyPath)]" />