Возможно, вы захотите подумать об этом в два этапа; во-первых, сделать преобразование, которое разрушает эти атрибуты значения, тогда их довольно тривиально считать.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@value">
<xsl:call-template name="breakdown">
<xsl:with-param name="itemlist" select="substring-before(substring-after(.,'['),']')" />
</xsl:call-template>
</xsl:template>
<xsl:template name="breakdown">
<xsl:param name="itemlist" />
<xsl:choose>
<xsl:when test="contains($itemlist,',')">
<xsl:element name="value">
<xsl:value-of select="normalize-space(substring-before($itemlist,','))" />
</xsl:element>
<xsl:call-template name="breakdown">
<xsl:with-param name="itemlist" select="substring-after($itemlist,',')" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:element name="value">
<xsl:value-of select="normalize-space($itemlist)" />
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Помимо «все» шаблон в нижней части, это поднимает любые значения атрибутов в формате, который вы дали, и разбивает их на отдельные элементы (как суб-элементы «metadata_valuelist» элемент) как это:
...
<metadata_valuelist>
<value>SampleItem1</value>
<value>SampleItem2</value>
</metadata_valuelist>
...
«подстрока-до/подстрока-после выбора вы видите вблизи верхних полос выключить„[“и„]“перед передачей его в„пробоя“шаблона. Этот шаблон будет проверять, есть ли запятая в его параметре itemlist, и если он выплескивает текст перед ним как содержимое элемента value, прежде чем рекурсивно называть себя с остальной частью списка. Если в параметре не было запятой, он просто выводит все содержимое параметра как элемент «значение».
Тогда просто запустить это:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:key name="itemvalue" match="value" use="text()" />
<xsl:template match="/">
<xsl:value-of select="count(//value[generate-id(.) = generate-id(key('itemvalue',.)[1])])" />
</xsl:template>
</xsl:stylesheet>
на XML вы получите от первого преобразования, и это будет просто выплюнуть одно значение в качестве вывода текста, который говорит вам, сколько различных значений у вас есть.
EDIT: Я, вероятно, следует отметить, это решение делает несколько предположений о вашем входе:
- Там нет атрибутов с именем «значение» где-либо в документе; если есть, вы можете изменить соответствие @value, чтобы выбрать их.
- В документе нет элементов с именем «значение»; так как первое преобразование создает их, второе не сможет отличить их. Если есть, вы можете заменить две строки
<xsl:element name="value">
на имя элемента, которое еще не используется.
- Содержимое атрибута @value всегда начинается с '[' и заканчивается на ']', и в списке нет ']' символов; если есть, то функция «подстрока перед» будет отбрасывать все после первого «]», а не только «]» в конце.
- В именах элементов, которые вы хотите подсчитать, нет запятых, например. [SampleItem1, «Sample2,3»]. Если есть, «Sample2» и «3» будут рассматриваться как отдельные элементы.
Это решение дает ожидаемый результат в данном конкретном случае. Однако при использовании следующих значений: '[SampleItem3]', '[SampleItem1SampleItem2, SampleItem2]', '[SampleItem1, SampleItem1SampleItem2]' - он вызывает неверный ответ: 3. Правильный ответ: 4. –
Это довольно аккуратное решение; Незначительная точка, но вам не нужен элемент ' ' вверху? –
Flynn1179
@ Dimitre: Вы правы! Я отредактировал ответ. Кроме того, я ищу решение, не раздвигая дерево дважды. – 2010-06-24 13:38:38