Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XPath to get Unique Element Names

Tags:

xslt

xpath

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 them? (I'm using Firefox's XPath engine.)

like image 351
mawrya Avatar asked Dec 31 '09 23:12

mawrya


People also ask

How can I get distinct values in XPath?

We can use distinct-values function which is available in XPath 2.0 for finding the unique values. The fn:distinct-values function returns a sequence of unique atomic values from $arg . Values are compared based on their typed value.

What is unique attribute in XML?

<xsd:unique> ElementSpecifies that an attribute or element value (or a combination of attribute or element values) must be unique within the specified scope.

What is a unique element in HTML?

The unique element defines that an element or an attribute value must be unique within the scope. The unique element MUST contain the following (in order): one and only one selector element (contains an XPath expression that specifies the set of elements across which the values specified by field must be unique)


2 Answers

Valid in XPath 2.0:

distinct-values(//*/name())
like image 111
Patrick Avatar answered Oct 23 '22 15:10

Patrick


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>
like image 38
Mads Hansen Avatar answered Oct 23 '22 16:10

Mads Hansen