2009-12-31 6 views
5

Я хочу использовать XPath для получения списка имен всех элементов, которые появляются в файле XML. Тем не менее, я не хочу, чтобы имена повторялись, поэтому элемент с тем же именем, что и предыдущий элемент, не должен совпадать. До сих пор у меня есть:XPath, чтобы получить уникальные имена элементов

*[not(local-name() = local-name(preceding::*))] 

Это нормально, но оно выплевывает дубликаты. Почему он выплевывает дубликаты и как я могу их устранить? (Я использую Firefox XPath engine.)

+0

Ваш код надморских кос потому что список не упорядочен. Он будет работать в упорядоченном списке. –

ответ

5

Вы получаете дубликаты, потому что ваш фильтр не оценивает то, как вы думаете.

Локальное имя-() функция возвращает локальное имя первого узла в набор узлов.

Единственный раз, когда ваш предикатный фильтр работал, если элемент имеет то же имя, что и первый предшествующий элемент.

Я не думаю, что вы сможете выполнить то, что хотите, с чистым XPATH 1.0 soultion. Вы можете сделать это в XPATH 2.0, но это не сработает с Firefox.

В XSLT вы можете использовать meunchien method, чтобы добиться того, чего вы хотите.

Ниже приведен пример. Вы не предоставили какой-либо образец XML, поэтому я все это очень общий (например, // * совпадает для всех элементов в документ):

<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> 
+0

Спасибо за подсказку. Вы правы в локальном имени(), возвращающем первый узел.Я на самом деле хотел отметить это как принятый ответ, но нажал неправильную галочку. Тем не менее, я действительно делал фильтрацию в javascript, поэтому оба этих ответа являются частью моего решения. Благодарю. – mawrya

1

Я бы порекомендовал сначала получить список всех элементов, а затем перебрать их по списку и добавить их в словарь для обнаружения дубликатов.

Например, в псевдокоде:

var allElements = doc.select("//node()"); 
var distinctElementTypes = new object(); 
foreach (var elem in allElements) { 
    distinctElementTypes[elem.name] = elem.name; 
} 

А теперь distinctElementTypes будет словаря различных имен элементов.

+0

Спасибо за ответ. Я мог бы использовать этот подход, но для xpath требуется только одна строка кода. Кроме того, это именно тот тип проблемы, для которого предназначен xpath. Я хотел бы знать, что не так с приведенным примером, так как я хочу продолжить образование по xpath. Насколько я могу судить, он должен работать, но это не так. – mawrya

+0

Я не уверен, почему «предыдущий» не работает. Может быть, он сравнивается только с предыдущими узлами-братьями рассматриваемого узла, а не с * всеми * предшествующими узлами? – Eilon

+0

Это была бы предыдущая ось. W3C говорит: предыдущая ось содержит все узлы в том же документе, что и контекстный узел, который находится перед узлом контекста в порядке документа, за исключением любых предков и исключая узлы узлов и узлы пространства имен. Итак, я могу понять, почему я могу получить дубликаты, если элементы с тем же именем являются предками, но я получаю дубликаты от элементов родного брата! – mawrya

6

Действительно в XPath 2.0:

distinct-values(//*/name()) 
Смежные вопросы