After toying with some XPath’s and a fair amount of XSL lately (& getting lost in XPath), I feel it would be wise to place something here to look back on…

Marcus Tucker, introduced me to Stylus Studio of which I am very thankful as XmlSpy didn’t help me to deduce the problem with one of the XPaths, (infact ‘Select Previous Link’)

So heres some snippets.

Select Previous Link – Select First Preceding Node @id with with specified PathID
//project/article[@id=$PathID]/preceding-sibling::article[1]/@id
Select Next Link – Select Following Sibling @id with with specified PathID
//project/article[@id=$PathID]/following-sibling::article/@id

Also using the following are very handy for helping you know where abouts you are:
<xsl:copy-of select=”parent::*”>
<xsl:copy-of select=”position()”>

<xsl:template match="*" mode="namespace">
   <xsl:for-each select="namespace::*">
      <xsl:if test="not(../ancestor::*[namespace::*[name() = name(current()) and . = current()]][last()])">
         <xsl:value-of select="name(..)" /> defines <xsl:text />
         <xsl:choose>
            <xsl:when test="name()">xmlns:<xsl:value-of select="name()" /></xsl:when>
            <xsl:otherwise>xmlns</xsl:otherwise>
         </xsl:choose>
         <xsl:text />="<xsl:value-of select="." />"<xsl:text />
      </xsl:if>
   </xsl:for-each>
</xsl:template>

  <!-- generate namespace declarations as needed for current
	element node and its attributes.
  -->
  <xsl:template name="findNamespace">
    <xsl:variable name="curnode" select="." />

    <xsl:for-each select=".|@*">
      <xsl:variable name="vName" select="substring-before(name(), ':')"/>
      <xsl:variable name="vUri" select="namespace-uri(.)"/>

      <xsl:variable name="vAncestNamespace">
        <xsl:call-template name="findAncNamespace">
          <xsl:with-param name="pName" select="$vName"/>
          <xsl:with-param name="pUri" select="$vUri"/>
          <xsl:with-param name="pNode" select="$curnode" />
        </xsl:call-template>
      </xsl:variable>

      <xsl:if test="not(number($vAncestNamespace))">
        <!-- not sure if "parent::*" should be "$curnode/parent::*" -->
        <xsl:if test="parent::* or namespace-uri() or contains(name(), ':')">
          <xsl:text> </xsl:text>
          <span>
            <xsl:value-of select="'xmlns'"/>
            <xsl:if test="contains(name(), ':')">
              <xsl:value-of select="concat              (':', $vName)"/>
            </xsl:if>
          </span>
          <span>="</span>
          <span>
            <xsl:value-of select="namespace-uri()"/>
          </span>
          <span>"</span>
        </xsl:if>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>

  <!-- Return 1 if an ancestor of pNode (or an attribute thereof)
    has the same prefix (pName) and namespace-uri (pUri) as
    the current node, and there is no closer ancestor (or attribute
    thereof) that has the same prefix but a different namespace-uri. Return 0 otherwise. -->
  <xsl:template name="findAncNamespace">
    <xsl:param name="pNode" select="."/>
    <xsl:param name="pName" select="substring-before(name(), ':')"/>
    <xsl:param name="pUri" select="namespace-uri(.)"/>

     <xsl:choose>
      <xsl:when test="not($pNode/parent::*)">0</xsl:when>
      <xsl:otherwise>
        <xsl:choose>
          <xsl:when test="($pNode/.. | $pNode/../@*)
          [$pName = substring-before(name(), ':') and
          $pUri = namespace-uri()]">
            1
          </xsl:when>
          <xsl:when test="($pNode/.. | $pNode/../@*)
          [$pName = substring-before(name), ':')]">
          <!-- and $pUri !=namespace-uri() -->
            0
          </xsl:when>
          <xsl:otherwise>
            <xsl:call-template name="findAncNamespace">
              <xsl:with-param name="pNode" select="$pNode/.."/>
              <xsl:with-param name="pName" select="$pName"/>
              <xsl:with-param name="pUri" select="$pUri"/>
            </xsl:call-template>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:otherwise>
    </xsl:choose>

  </xsl:template>

I also wrote up some XSL to retreive parameters from XSL being parsed on the client, now I haven’t tested this although it may be beneficial to someone trying to extract parameters on the client-side.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:eg="http://schemas.example.com/"
>
<xsl:output
  omit-xml-declaration="yes"
  method = "html"
  indent = "no"
  encoding = "UTF-8"

/>
<msxsl:script language="JScript" implements-prefix="eg">
  function GetParam(name) {
    var start=location.search.indexOf("?"+name+"=");
    if (start<0) start=location.search.indexOf("&"+name+"=");
    if (start<0) return '';
    start += name.length+2;
    var end=location.search.indexOf("&",start)-1;
    if (end<0) end=location.search.length;
    var result=location.search.substring(start,end);
    var result='';

    for(var i=start;i<=end;i++) {
      var c=location.search.charAt(i);
        result=result+(c=='+'?' ':c);
      }
      return unescape(result);
    }
</msxsl:script>

<xsl:template match="/">
  <xsl:value-of select="eg:GetParam('Query')" />
</xsl:template>
<xsl:stylesheet>