2013-04-07 18 views
8

Я думал, что увидел ошибку в ответе this question и указал на нее. Мне сказали, что я ошибался, и мой ответ был удален.Соответствующие дочерние элементы в XSL

Я все еще не понимаю, как я ошибался. Поэтому я размещаю здесь и надеюсь, что кто-то может объяснить мне свое недоразумение.

Ответ, на который я ответил, объяснил использование шаблонов apply-templates. Он содержал следующие XML и XSL, описывая, как шаблоны будут соответствовать:

<!-- sample XML snippet --> 
<xml> 
    <foo /><bar /><baz /> 
</xml> 

<!-- sample XSLT snippet --> 
<xsl:template match="xml"> 
    <xsl:apply-templates select="*" /> <!-- three nodes selected here --> 
</xsl:template> 

<xsl:template match="foo"> <!-- will be called once --> 
    <xsl:text>foo element encountered</xsl:text> 
</xsl:template> 

<xsl:template match="xml/*"> <!-- will be called twice --> 
    <xsl:text>other element countered</xsl:text> 
</xsl:template> 

Мой комментарий был, что последний шаблон в должен быть:

<xsl:template match="*"> <!-- will be called twice --> 
    <xsl:text>other element countered</xsl:text> 
</xsl:template> 

, потому что текущий узел уже <xml>

мне сказали:

Нет, XML/* это шаблон, который соответствует дочерние элементы элемента с имя xml.

Тестирование оригинальный ответ

Однако с этим XML:

<xml> 
    <foo /><bar /><baz /> 
</xml> 

И этот XSL таблицы стилей (заполнение фрагмента кода выше):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text"/> 

<xsl:template match="xml"> 
    <xsl:apply-templates select="*" /> <!-- three nodes selected here --> 
</xsl:template> 

<xsl:template match="foo"> <!-- will be called once --> 
    <xsl:text>foo element encountered.&#xa;</xsl:text> 
</xsl:template> 

<xsl:template match="xml/*"> <!-- will be called twice --> 
    <xsl:text>other element countered.&#xa;</xsl:text> 
</xsl:template> 

</xsl:stylesheet> 

Я получаю :

other element countered. 
other element countered. 
other element countered. 

Тестирование мой 'исправленную' версию

Если я заменить последний шаблон с:

<xsl:template match="*"> <!-- will be called twice --> 
    <xsl:text>other element countered.&#xa;</xsl:text> 
</xsl:template> 

как на мой ответ, я получаю:

foo element encountered. 
other element countered. 
other element countered. 

, который, казалось бы, быть верным.

Надеюсь, мой вопрос не нарушит никаких рекомендаций, но я не вижу, что я ошибаюсь и надеюсь, что кто-то сможет объяснить его более полно.

PS. Я боюсь, что мой оригинальный ответ на другой вопрос был отправлен как ответ, а не комментарий, так как у меня недостаточно очков, чтобы оставлять комментарии. Я не был уверен, что лучше всего делать ...

+1

Спасибо, что нашли эту тупую ошибку, теперь она исправлена ​​в другой теме. Это оставалось незамеченным всеми, кто смотрел на ответ на протяжении многих лет. – Tomalak

ответ

6

Это правильно, согласно rules on the default priority of templates. Шаблон, соответствующий foo, имеет приоритет по умолчанию 0, один из которых соответствует * имеет приоритет по умолчанию -0,5, но один соответствующий xml/* имеет приоритет по умолчанию 0,5. Шаблон xml/* считается более конкретным, чем foo, поэтому он выигрывает, когда любой из них может совпадать.

Таким образом, вы были правы, что выражение матча шаблона нужно быть *, а не xml/*, но не по правильным причинам - в xml/* шаблоне может матча для apply-templates select="*", когда текущий узел xml, и он будет применяться к любой из этих выбранных элементов (поскольку все они являются дочерними числами xml), за исключением тех случаев, когда имеется еще один шаблон с явным priority, превышающим 0,5, который может иметь приоритет.

4

Я был человеком, который сказал, что вы неверны в другой теме, и, внимательно посмотрев на вопрос, я вижу, что вы были правы, указав, что Томалак допустил ошибку, но не по причинам, которые вы дали (если я правильно понимаю ваш комментарий). match="xml/*" соответствует дочерним узлам элемента <xml>, независимо от того, был ли текущий контекст узлом <xml>, когда был вызван apply-templates. В выражении match="" «текущий узел» является узлом, на котором применяются шаблоны, а не контекстом, в котором был вызван apply-templates, поэтому в этом шаблоне текущий узел будет foo, bar и baz. Вы можете наблюдать из своих собственных экспериментов выше, что xml/* действительно удается сопоставить дочерние элементы xml, но на самом деле соответствует им больше, чем Томалак говорит, что это будет.

Проблема с match="xml/*" заключается в том, что это слишком специфично и имеет противоположный эффект от того, что я думаю, что Томалак предназначен. Похоже, он имел в виду, что это было уловкой для детей xml, которые не соответствовали друг другу, но, как объясняет Ян Робертс, этот шаблон заканчивается приоритетом , чем шаблон foo, и ловит всех детей узел xml.

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

+0

+1 Ну, это неловко. :) – Tomalak

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