XPath to get Unique Element Names
I want to use XPath to get a list of the names of all the elements that appear in an XML file. However, I don't want any names repeated, so an element with the same name as a preceding element should not be matched. So far, I've got:
*[not(local-name() = local-name(preceding::*))]
This executes alright but it spits out duplicates. Why does it spit out the duplicates and how can I eliminate the开发者_如何学编程m? (I'm using Firefox's XPath engine.)
Valid in XPath 2.0:
distinct-values(//*/name())
You are getting duplicates because your filter is not evaluating the way you think it is.
The local-name() function returns the local name of the first node in the nodeset.
The only time your predicate filter would work is if the element happened to have the same name as the first preceding element.
I don't think you will be able to accomplish what you want with a pure XPATH 1.0 soultion. You could do it in XPATH 2.0, but that would not work with Firefox.
In XSLT you can use the meunchien method to accomplish what you want.
Below is an example. You didn't provide any sample XML, so I kept it very generic(e.g. //* matches for all elements in the doc):
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"><xsl:output method="xml"/>
<xsl:key name="names" match="//*" use="local-name(.)"/>
<xsl:template match="/">
<xsl:for-each select="//*[generate-id(.) = generate-id(key('names', local-name(.)))]">
<!--Do something with the unique list of elements-->
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
I would recommend first getting a list of all elements and then iterate through the list and add them to a dictionary to detect duplicates.
For example, in pseudo-code:
var allElements = doc.select("//node()");
var distinctElementTypes = new object();
foreach (var elem in allElements) {
distinctElementTypes[elem.name] = elem.name;
}
And now distinctElementTypes will be a dictionary of distinct element names.
精彩评论