попытаться инкапсулировать генерацию старшей диаграммы в событии просмотра страницы
$(document).on("pageshow", "#hg_graph", function() {...});
Эту проблему довольно легко решить с помощью XPath. Вот выражение, которое вы ищете: count ((. | Previous-sibling :: ROLE) [not (@name = previous-sibling :: ROLE / @ name)])
Это можно разбить чтобы сделать его более читабельным, как я сделал в следующей таблице стилей XSLT 1.0:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<!-- don't copy whitespace -->
<xsl:template match="text()"/>
<xsl:template match="ROLE">
<xsl:variable name="roles-so-far" select=". | preceding-sibling::ROLE"/>
<!-- Only select the first instance of each ROLE name -->
<xsl:variable name="roles-so-far-unique"
select="$roles-so-far[not(@name = preceding-sibling::ROLE/@name)]"/>
<xsl:apply-templates select="@name"/>
<xsl:text> </xsl:text>
<xsl:value-of select="count($roles-so-far-unique)"/>
<xsl:text>
</xsl:text> <!-- linefeed -->
</xsl:template>
</xsl:stylesheet>
Вот альтернативная реализация, использующая метод Мюнчи. Сначала объявите ключ:
<xsl:key name="roles" match="ROLE" use="@name"/>
Затем замените определение $ role-so-far-unique на что-то вроде этого:
<!-- Among all the ROLEs having one of the names so far,
select only the first one for each name -->
<xsl:variable name="roles-so-far-unique"
select="../ROLE[@name = $roles-so-far/@name]
[generate-id(.) = generate-id(key('roles',@name)[1])]"/>
Этот код, конечно, более сложный. Если у вас нет большого набора данных, требующего от вас ускорения обработки с использованием метода Мюнчи (даже в этом случае я бы проверил, что он вам что-нибудь пригодится), вы также можете придерживаться более простой версии, приведенной выше.
Наконец, в XSLT 2.0, это намного проще.
Рекурсия обычно хорошо работает с такими проблемами.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" media-type="text/plain" />
<xsl:template name="count-previous-but-not-with-my-name">
<xsl:param name="nodes" />
<xsl:param name="count" select="0" />
<xsl:choose>
<xsl:when test="count($nodes) = 0">
<xsl:value-of select="$count" />
</xsl:when>
<xsl:otherwise>
<xsl:variable name="last-name" select="$nodes[last()]/@name" />
<xsl:variable name="nodes-before-me-without-my-name" select="$nodes[position() < last() and @name != $last-name]" />
<xsl:call-template name="count-previous-but-not-with-my-name">
<xsl:with-param name="nodes" select="$nodes-before-me-without-my-name" />
<xsl:with-param name="count" select="$count + 1" />
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="/">
<xsl:for-each select="//ROLEACTIONINFO/ROLE">
<xsl:variable name="role" select="current()" />
<xsl:variable name="my-pos" select="position()" />
<xsl:value-of select="current()/@name" /><xsl:text> </xsl:text>
<xsl:call-template name="count-previous-but-not-with-my-name">
<xsl:with-param name="nodes" select="$role/../ROLE[position() <= $my-pos]" />
</xsl:call-template>
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Это легко решается с помощью
:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output method="text" />
<xsl:key name="kRole" match="ROLE" use="@name" />
<xsl:template match="ROLE">
<xsl:value-of select="concat(@name, ' ')" />
<xsl:value-of select="count(
(. | preceding-sibling::ROLE)[
count(. | key('kRole', @name)[1]) = 1
])" />
</xsl:template>
</xsl:stylesheet>
Результат такой, как нужно:
TESTER 1
PARENT1 2
PARENT1 2
PARENT1 2
PARENT2 3
PARENT2 3
PARENT3 4
PARENT4 5
TESTROLE 6
Объяснение выражения XPath в
:
count( # count the nodes:
(. | preceding-sibling::ROLE) # union of this node and its predecessors
[ # where...
count( # the count of the union of...
. | # this node and
key('kRole', @name)[1] # the first node with the same @name
) = 1 # is 1
]
)
Это метод Мюнчи. Основываясь на том факте, что набор узлов не может содержать один и тот же узел дважды, объединение двух узлов имеет счетчик узлов 1, если они являются одним и тем же узлом. Таким образом, мы выбираем уникальные узлы только из (. | Previous-sibling :: ROLE)
.
Если в вашем документе более одного элемента
, отсутствует родительская проверка. Этого также легко достичь:
<xsl:template match="ROLE">
<xsl:variable name="parentId" select="generate-id(..)" />
<xsl:value-of select="count(
(. | preceding-sibling::ROLE)[
count(. | key('kRole', @name)[generate-id(..) = $parentId][1]) = 1
])" />
</xsl:template>
Обратите внимание, что [generate-id (..) = $ parentId] [1]
! = [1] [generate-id (..) = $ parentId]
.
Порядок важен при связывании предикатов. Первый сначала проверяет равенство родительских узлов, а затем берет первый уникальный узел из сокращенного набора. Это то, что мы хотим.
Последний берет первый узел из набора (все узлы ROLE с заданным именем по всему документу), берет первый и затем сохраняет или отбрасывает его на основе родительского равенства. Это неправильно.
ROLE) только . Если в вашем документе более одного элемента
, значит родительская проверка отсутствует. Этого также легко достичь:
<xsl:template match="ROLE">
<xsl:variable name="parentId" select="generate-id(..)" />
<xsl:value-of select="count(
(. | preceding-sibling::ROLE)[
count(. | key('kRole', @name)[generate-id(..) = $parentId][1]) = 1
])" />
</xsl:template>
Обратите внимание, что [generate-id (..) = $ parentId] [1]
! = [1] [generate-id (..) = $ parentId]
.
Порядок важен при связывании предикатов. Первый сначала проверяет равенство родительских узлов, а затем берет первый уникальный узел из сокращенного набора. Это то, что мы хотим.
Последний берет первый узел из набора (все узлы ROLE с заданным именем по всему документу), берет первый и затем сохраняет или отбрасывает его на основе родительского равенства. Это неправильно.
ROLE) только . Если в вашем документе более одного элемента
, значит родительская проверка отсутствует. Этого также легко достичь:
<xsl:template match="ROLE">
<xsl:variable name="parentId" select="generate-id(..)" />
<xsl:value-of select="count(
(. | preceding-sibling::ROLE)[
count(. | key('kRole', @name)[generate-id(..) = $parentId][1]) = 1
])" />
</xsl:template>
Обратите внимание, что [generate-id (..) = $ parentId] [1]
! = [1] [generate-id (..) = $ parentId]
.
Порядок важен при связывании предикатов. Первый сначала проверяет равенство родительских узлов, а затем берет первый уникальный узел из сокращенного набора. Это то, что мы хотим.
Последний берет первый узел из набора (все узлы ROLE с заданным именем по всему документу), берет первый и затем сохраняет или отбрасывает его на основе родительского равенства. Это неправильно.
Этого также легко достичь: <xsl:template match="ROLE">
<xsl:variable name="parentId" select="generate-id(..)" />
<xsl:value-of select="count(
(. | preceding-sibling::ROLE)[
count(. | key('kRole', @name)[generate-id(..) = $parentId][1]) = 1
])" />
</xsl:template>
Обратите внимание, что [generate-id (..) = $ parentId] [1]
! = [1] [generate-id (..) = $ parentId]
.
Порядок важен при связывании предикатов. Первый сначала проверяет равенство родительских узлов, а затем берет первый уникальный узел из сокращенного набора. Это то, что мы хотим.
Последний берет первый узел из набора (все узлы ROLE с заданным именем по всему документу), берет первый и затем сохраняет или отбрасывает его на основе родительского равенства. Это неправильно.
Этого также легко достичь: <xsl:template match="ROLE">
<xsl:variable name="parentId" select="generate-id(..)" />
<xsl:value-of select="count(
(. | preceding-sibling::ROLE)[
count(. | key('kRole', @name)[generate-id(..) = $parentId][1]) = 1
])" />
</xsl:template>
Обратите внимание, что [generate-id (..) = $ parentId] [1]
! = [1] [generate-id (..) = $ parentId]
.
Порядок важен при связывании предикатов. Первый сначала проверяет равенство родительских узлов, а затем берет первый уникальный узел из сокращенного набора. Это то, что мы хотим.
Последний берет первый узел из набора (все узлы ROLE с заданным именем по всему документу), берет первый и затем сохраняет или отбрасывает его на основе родительского равенства. Это неправильно.
Последний берет первый узел из набора (все узлы ROLE с заданным именем по всему документу), берет первый и затем сохраняет или отбрасывает его на основе родительского равенства. Это неправильно.
Последний берет первый узел из набора (все узлы ROLE с заданным именем по всему документу), берет первый и затем сохраняет или отбрасывает его на основе родительского равенства. Это неправильно.