Я хочу использовать XPath для получения списка названий всех элементов, которые появляются в XML-файле. Однако я не хочу повторенных имен, таким образом, элемент с тем же именем как предыдущий элемент не должен быть подобран. До сих пор я имею:
*[not(local-name() = local-name(preceding::*))]
Это выполняется хорошо, но это выкладывает дубликаты. Почему это выкладывает дубликаты и как я могу устранить их? (Я использую механизм XPath Firefox.)
Вы получаете дубликаты, потому что ваш фильтр не оценивает то, что вы думаете.
Функция local-name() возвращает локальное имя первого узла в узле.
Единственный раз, когда ваш предикатный фильтр будет работать, это если элемент случайно будет иметь то же имя, что и первый предыдущий элемент.
Я не думаю, что вы сможете выполнить то, что вы хотите с чистой XPATH 1.0 душой. Вы могли бы сделать это в XPATH 2.0, но это не сработает с Firefox.
В XSLT вы можете использовать meunchien метод для достижения того, что вы хотите.
Ниже приведен пример. Вы не предоставили никакого примера XML, поэтому я сохранил его очень общим (например, //* совпадения для всех элементов в 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>
Я бы порекомендовал сначала получить список всех элементов, а затем выполнить итерацию по списку и добавить их в словарь для обнаружения дубликатов.
Например, в псевдокоде:
var allElements = doc.select("//node()");
var distinctElementTypes = new object();
foreach (var elem in allElements) {
distinctElementTypes[elem.name] = elem.name;
}
А теперь distinctElementTypes будет словарь с разными именами элементов.
.Действителен в XPath 2.0:
distinct-values(//*/name())