0

Is is possible to get all the xPaths used in an XSLT file?

For example:

XSLT File:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <html>
            <body>
                <h2>My CD Collection</h2>
                <table border="1">
                    <tr bgcolor="#9acd32">
                        <th>Title</th>
                        <th>Artist</th>
                    </tr>
                    <xsl:for-each select="/catalog/cd">
                        <tr>
                            <td>
                                <xsl:value-of select="title"/>
                            </td>
                            <td>
                                <xsl:value-of select="artist"/>
                            </td>
                        </tr>
                    </xsl:for-each>                    
                </table>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

As output I want a list like this:

/catalog/cd
/catalog/cd/title
/catalog/cd/artist

Maybe by making a custom post processor that outputs a line everytime an xPaths has matched/not been matched? Ideas are welcome, because I'm very hopeless :) Thanks!

  • What would be the purpose of this? – michael.hor257k Aug 24 '17 at 15:05
  • I'm making an integration. In the software I can define xml paths which exports data. In some cases more xml paths are exported than there are used in the XSLT. So with this I can see which xPaths are used. – GalaxyBounce Aug 24 '17 at 15:32
  • 1
    I don't think this is possible. A path can be relative, and in order to make it absolute, you would need to append it to the current context path, which could be anywhere in the stylesheet - e.g. the same named template can be called from different contexts. -- Also, whether a path has been actually used depends on the XML input. – michael.hor257k Aug 24 '17 at 15:36

2 Answers2

0

You can use this:

 <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:template match="*">
            <xsl:for-each select="ancestor-or-self::*">
                <xsl:text>/</xsl:text>
                <xsl:value-of select="local-name(.)"/>
            </xsl:for-each>
        <xsl:apply-templates/>
    </xsl:template>
 </xsl:stylesheet>
Rupesh_Kr
  • 3,395
  • 2
  • 17
  • 32
  • Thanks for your response!I also though of that solution, but then I get all the xPaths and not only the ones that are used in the xsl – GalaxyBounce Aug 24 '17 at 15:27
0

It's difficult because template rule matching in XSLT is very dynamic: if you have a template with match="cities" that calls xsl:apply-templates, and if you have another template with match="city", then the XSLT compiler can't know that there is a path /cities/city.

Internally Saxon has the capability to build a "path map" rather as you describe, and it's used to implement "document projection" in XQuery, but it's of very little use in XSLT because of dynamic template rule despatch.

So static analysis to determine the paths isn't going to get you very far. You also suggest that dynamic analysis - capturing the paths visited at run-time - might also be of interest. In principle you can do that in Saxon with a TraceListener. The difficulty is in determining exactly what you mean by "visited" - for example do you consider xsl:copy-of select="/" as visiting every node in the document, or only the root node?

Michael Kay
  • 156,231
  • 11
  • 92
  • 164