[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message] Re: Getting the XPath of a node
On Wednesday 04 September 2002 02:03, Dennis wrote: > Say if I have following XML: > <Person id="12345"> > <Name>Dennis</Name> > <Company>Netscape</Company> > <Address>Mountain View</Address> > <Email>dennis@xxxxxxxxxxxx</Email> > </Person> > > ----The XSL to print XPath--- > <xsl:template match="Company"> > //Print the XPath of Company as /Person/Company > </xsl:template> > More templates corresponding to each element. If you use Saxon exclusively, first check out <http://saxon.sourceforge.net/saxon6.5.2/extensions.html#path>. If that doesn't help, then I guess the question I need to ask is, do you want to output an XPath that identifies a specific <Company> element (as in "/Person[@id='12345']/Company" or "/Person[1]/Company[1]"), or any <Company> in the whole document ("/Person/Company", as you indicate). If your answer is the former, then there are several ways you can do it. One would be to figure out a set of parameters that fully specify the location of the node in the document, which are specific to that particular type of node. For example, to identify a <Company>, you need to know Person/@id. If you want to do this for every type of element, then you can just write a bunch of custom templates: <xsl:template match="Company"> Person[@id='<xsl:value-of select="parent::Person/@id"/>']/Company </xsl:template> and so on. If you want a more generic solution, then you can go the route that saxon:path() uses, which is to simply use the position of the element and its parents within the document, which gives you something like "/Person[1]/Company[1]". To do this, the basic idea would be to select each of the ancestors of the node in reverse document order. You could probably mangle xsl:for-each and xsl:sort to do this, but I prefer a recursive template (untested): <template match="*" name="output-xpath"> <param name="node" select="."/> <text>/</text> <value-of select="name($node)"/> <text>[</text> <value-of select="count($node/../*[local-name() = local-name($node) and namespace-uri() = namespace-uri($node)])"/> <text>]</text> <if test=".."> <call-template name="output-xpath"> <with-param name="node" select="$node/.."/> </call-template> </if> </template> [The above only works for elements (assuming it works at all, I haven't tested), so if you want to adapt it to text or other types of nodes, then all you should need is a big <xsl:choose> to special case outputting of "text()", processing-instruction()", etc.] If you just want the XPath to identify *any* <Company> in the whole document, then you should be able to use the same template as above but just without the predicate stuff (the '[' + count() + ']'). HTH -- Peter Davis XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
|
PURCHASE STYLUS STUDIO ONLINE TODAY!Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced! Download The World's Best XML IDE!Accelerate XML development with our award-winning XML IDE - Download a free trial today! Subscribe in XML format
|