I. XSLT 1.0/XPath 1.0
I don't believe there is a way to do this with pure XPath 1.0 (since you are looking for distinct element names that are, I assume, not in any particular order [at any rate, I don't like to rely on there being some sort of order]).
That said, you can use a key-based XSLT 1.0 solution to solve the problem.
When this XSLT 1.0 document:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output omit-xml-declaration="no" indent="yes" method="text"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kFilmChildren" match="film/*" use="name()"/>
<xsl:template match="/">
<xsl:value-of
select="count(//film/*[
generate-id() =
generate-id(key('kFilmChildren', name())[1])
])"/>
</xsl:template>
</xsl:stylesheet>
...is applied against your sample XML (wrapped in a root element):
<films>
<film>
<title/>
<year/>
<actor/>
</film>
<film>
<title/>
<year/>
<actor/>
</film>
</films>
...the wanted result is produced:
3
If we apply the same stylesheet against a slightly modified XML:
<films>
<film>
<title/>
<year/>
<actor/>
<test/>
</film>
<film>
<title/>
<year/>
<actor/>
<test/>
<test2/>
</film>
</films>
...again, the correct answer is produced:
5
NOTE: given that you did not show a complete document, I made up for that lacking knowledge by using the //
expression. That, however, can be an expensive operation near the root of very large trees; you would do well to make yours more specific.
II. XSLT 2.0/XPath 2.0
Pure XPath 2.0 can be used to obtain the correct answer by utlizing the distinct-values
expression:
count(distinct-values(//film/*/name()))
XSLT Verification:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output omit-xml-declaration="no" indent="yes" method="text" />
<xsl:strip-space elements="*" />
<xsl:template match="/">
<xsl:value-of select="count(distinct-values(//film/*/name()))" />
</xsl:template>
</xsl:stylesheet>
Result:
3