2009-03-23 2 views
3

Я написал несколько XSLT, которые используют один XML-документ для фильтрации другого. Теперь я хотел бы указать свои выходные элементы, используя position(), но мое условие фильтрации не встроено в мой <xsl:for-each>, поэтому position() дает мне результаты с нумерационными пробелами. Как избавиться от пробелов?XSLT-фильтр с индексным счетчиком

<xsl:variable name="Astring"> 
    <a><b>10</b><b>20</b><b>30</b></a> 
</xsl:variable> 
<xsl:variable name="A" select="msxml:node-set($Astring)" /> 

<xsl:variable name="Bstring"> 
    <c><d>20</d><d>30</d></c> 
</xsl:variable> 
<xsl:variable name="B" select="msxml:node-set($Bstring)" /> 

<e> 
    <xsl:for-each select="$A/a/b"> 
    <xsl:variable name="matchvalue" select="text()" /> 
    <xsl:if test="count($B/c/d[text() = $matchvalue]) &gt; 0"> 
     <xsl:element name="f"> 
     <xsl:attribute name="i"> 
      <xsl:value-of select="position()" /> 
     </xsl:attribute> 
     <xsl:copy-of select="text()" /> 
     </xsl:element> 
    </xsl:if> 
    </xsl:for-each> 
</e> 

Вот результат:

<e> 
    <f i="2">20</f> 
    <f i="3">30</f> 
</e> 

... но я хочу это:

<e> 
    <f i="1">20</f> 
    <f i="2">30</f> 
</e> 

Есть ли способ, чтобы включить выше тест <xsl:if> фильтрации внутри атрибута <xsl:for-each>select?

Примечание: я видел this question re: filtering и this one re: счетчики, но первый не подсчитывает своих результатов, а последний использует position().

ответ

3

Есть ли какая-то особая причина, по которой вы не можете включить свое условие в цикл for-each?

<xsl:for-each select="$A/a/b[$B/c/d = .]"> 

Я протестировал это в Visual Studio и отлично работает для этого примера.

Это был выход:

<e> 
    <f i="1">20</f> 
    <f i="2">30</f> 
</e> 
+0

Блестяще, спасибо! Я попытался переместить условие в мое для каждого, но встретил разочарование, пытаясь сделать это следующим образом: $ A/a/b [count ($ B/c/d [<некоторое условие соответствия здесь>])> 0] –

2

Я не уверен, почему люди всегда хотят использовать <xsl:for-each> когда <xsl:apply-templates> явно лучшая альтернатива.

Хорошо, это риторический. Я знаю, почему это так: <xsl:for-each> кажется проще. Но это не — следующие два шаблона заменить цельные для-каждой конструкции:

<xsl:template match="/"> 
    <e><xsl:apply-templates select="$B/c/d[$A/a/b = .]" /></e> 
</xsl:template> 

<xsl:template match="d"> 
    <f i="{position()}"><xsl:value-of select="." /></f> 
</xsl:template> 

Выход:

<e> 
    <f i="1">20</f> 
    <f i="2">30</f> 
</e> 

Ну, я обманул немного. Вы можете уплотнить версию <xsl:for-each> к этому:

<xsl:template match="/"> 
    <e> 
    <xsl:for-each select="$B/c/d[$A/a/b = .]"> 
     <f i="{position()}"><xsl:value-of select="." /></f> 
    </xsl:for-each> 
    </e> 
</xsl:template> 

Тем не менее, в нем отсутствует легкость <xsl:apply-templates> вариант, имхо.

+0

Люди, которые больше привыкли к традиционному программированию, вероятно, с трудом понимают, что происходит в этом образце. Люди просто более удобны с петлями. – Welbog

+0

Спасибо. По какой-то причине я колебался в применении шаблонов, зная, что мне нужна позиция() и еще не знаю, как это работает в шаблоне. Я согласен, что ваша ревизия загружена более элегантно. –

+0

@ Daniel Weaver: position() работает точно так же, как и для каждого: он возвращает позицию текущего узла в контексте _setlect_set_set_. Как только вы увидите атрибут «select =» для элемента XSL, создается новый контекст набора узлов, и в этом контексте будет работать position(). – Tomalak

Смежные вопросы