Here is a pure XSLT 1.0 transformation that produces the paths to all leaf elements in an XML documents (see also: Generate/get Xpath from XML in Java) :
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vApos">'</xsl:variable>
<xsl:template match="*[@* or not(*)] ">
<xsl:if test="not(*)">
<xsl:apply-templates select="ancestor-or-self::*" mode="path"/>
<xsl:value-of select="concat('=',$vApos,.,$vApos)"/>
<xsl:text>
</xsl:text>
</xsl:if>
<xsl:apply-templates select="@*|*"/>
</xsl:template>
<xsl:template match="*" mode="path">
<xsl:value-of select="concat('/',name())"/>
<xsl:variable name="vnumPrecSiblings" select=
"count(preceding-sibling::*[name()=name(current())])"/>
<xsl:if test="$vnumPrecSiblings">
<xsl:value-of select="concat('[', $vnumPrecSiblings +1, ']')"/>
</xsl:if>
</xsl:template>
<xsl:template match="@*">
<xsl:apply-templates select="../ancestor-or-self::*" mode="path"/>
<xsl:value-of select="concat('[@',name(), '=',$vApos,.,$vApos,']')"/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
When applied on the provided XML document:
<myroot>
<my2ndlvl>
<my3rdlvl foo="bar"/>
</my2ndlvl>
<my2ndlvl>
<my3rdlvl fum="baz"/>
</my2ndlvl>
</myroot>
the wanted output: a sequence of XPath expressions for every element in the document, is produced:
/myroot/my2ndlvl/my3rdlvl=''
/myroot/my2ndlvl/my3rdlvl[@foo='bar']
/myroot/my2ndlvl[2]/my3rdlvl=''
/myroot/my2ndlvl[2]/my3rdlvl[@fum='baz']
Do note: The XPath expression to the wanted element contains a comparison for its attribute, exactly as wanted.
One can easily modify this transformation to accept as parameter a single node (element) and produce the XPath expression to only this element.
Thus, after editing the above transformation we arrive at this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="pNode" select="/myroot/my2ndlvl/my3rdlvl[@fum='baz']"/>
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vApos">'</xsl:variable>
<xsl:template match="*">
<xsl:if test="descendant-or-self::*[count(. | $pNode) = 1]">
<xsl:value-of select="concat('/',name())"/>
<xsl:variable name="vnumPrecSiblings" select=
"count(preceding-sibling::*[name()=name(current())])"/>
<xsl:variable name="vnumFollowSiblings" select=
"count(following-sibling::*[name()=name(current())])"/>
<xsl:if test="$vnumPrecSiblings + $vnumFollowSiblings > 0">
<xsl:value-of select="concat('[', $vnumPrecSiblings +1, ']')"/>
</xsl:if>
<xsl:apply-templates select="* | @*"/>
</xsl:if>
</xsl:template>
<xsl:template match="@*">
<xsl:value-of select="concat('[@',name(), '=',$vApos,.,$vApos,']')"/>
</xsl:template>
</xsl:stylesheet>
And this produces exactly the wanted, correct result: a full and unambiguous XPath expression that selects exactly the node passed as parameter to the transformation, and explicitly tests/disambiguates using the attribute value of this element. The result is:
/myroot/my2ndlvl[2]/my3rdlvl[@fum='baz']
Not only this, but the generated XPath expression tests for all attributes of the element, if it has more than one attribute.
Modify the original XML document so that now the wanted element has two attributes: fum and test:
<myroot>
<my2ndlvl>
<my3rdlvl foo="bar"/>
</my2ndlvl>
<my2ndlvl>
<my3rdlvl fum="baz" test="xyz"/>
</my2ndlvl>
</myroot>
Applying the above transformation on this document now produces:
/myroot/my2ndlvl[2]/my3rdlvl[@fum='baz'][@test='xyz']
Isn't this wonderful ... !