Sometimes, you want to get the XPath of an element. Here are two working solutions, one in pure XSLT and one in C#.
Both of them return XPath in the form of: /html[1]/body[1]/div[1]/div[2]/div[3]/div[1]/p[2]/img[1]
C#
/// <summary> /// Gets the X-Path to a given Node /// </summary> /// <param name="node">The Node to get the X-Path from</param> /// <returns>The X-Path of the Node</returns> public string GetXPathToNode(XmlNode node) { if (node.NodeType == XmlNodeType.Attribute) { // attributes have an OwnerElement, not a ParentNode; also they have // to be matched by name, not found by position return String.Format("{0}/@{1}", GetXPathToNode(((XmlAttribute)node).OwnerElement), node.Name); } if (node.ParentNode == null) { // the only node with no parent is the root node, which has no path return ""; } // Get the Index int indexInParent = 1; XmlNode siblingNode = node.PreviousSibling; // Loop thru all Siblings while (siblingNode != null) { // Increase the Index if the Sibling has the same Name if (siblingNode.Name == node.Name) { indexInParent++; } siblingNode = siblingNode.PreviousSibling; } // the path to a node is the path to its parent, plus "/node()[n]", where n is its position among its siblings. return String.Format("{0}/{1}[{2}]", GetXPathToNode(node.ParentNode), node.Name, indexInParent); }
XSLT
<xsl:template name="GeneratePath"> <xsl:param name="node" select="." /> <xsl:message terminate="no"> <xsl:copy-of select="$node"/> </xsl:message> <xsl:apply-templates select="$node" mode="StartGeneratePath" /> </xsl:template> <xsl:template match="*" mode="StartGeneratePath"> <xsl:call-template name="genPath" /> </xsl:template> <xsl:template name="genPath"> <xsl:param name="prevPath"/> <xsl:variable name="currPath" select="concat('/',name(),'[',count(preceding-sibling::*[name() = name(current())])+1,']',$prevPath)"/> <xsl:for-each select="parent::*"> <xsl:call-template name="genPath"> <xsl:with-param name="prevPath" select="$currPath"/> </xsl:call-template> </xsl:for-each> <xsl:if test="not(parent::*)"> <xsl:value-of select="$currPath"/> </xsl:if> </xsl:template>
XSLT-Usage
<xsl:variable name="path"> <xsl:call-template name="GeneratePath"> <xsl:with-param name="node" select="./div[@class='eintrag2']//img[1]"/> </xsl:call-template> </xsl:variable>