2016-03-16 3 views
0

Это моя трансформация:Почему не самый специализированный шаблон матч в XSLT

<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="/root"> 
     <output> 
      <xsl:apply-templates select="outer[@type='foo']/inner"/> 
     </output> 
    </xsl:template> 

    <xsl:template match="outer[@type='foo']/inner[@type='bar1' or @type='bar2' or @type='bar3' or @type='bar4']"> 
     <item> 
      <xsl:value-of select="text()"/> 
     </item> 
    </xsl:template> 

    <xsl:template match="outer[@type='foo']/inner"> 
     <xsl:message terminate="yes"> 
      <xsl:value-of select="concat('Unexpected type: ', @type)"/> 
     </xsl:message> 
    </xsl:template> 
</xsl:transform> 

Это мой вход:

<root> 
    <outer type="foo"> 
     <inner type="bar2">bar2</inner> 
    </outer> 
</root> 

Когда я выполнить преобразование на входе, Xalan завершает работу с фатальная ошибка, вызванная <xsl:message terminate="yes"> в третьем <xsl:template>. Зачем? Не следует ли вместо второго, более специализированного матча <xsl:template>?

ответ

1

Другим решением было бы просто иметь торговые позиции 2 шаблонов:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="/root"> 
     <output> 
      <xsl:apply-templates select="outer[@type='foo']/inner"/> 
     </output> 
    </xsl:template> 
    <xsl:template match="outer[@type='foo']/inner"> 
     <xsl:message terminate="yes"> 
      <xsl:value-of select="concat('Unexpected type: ', @type)"/> 
     </xsl:message> 
    </xsl:template> 
    <xsl:template match="outer[@type='foo']/inner[@type='bar1' or @type='bar2' or @type='bar3' or @type='bar4']"> 
     <item> 
      <xsl:value-of select="text()"/> 
     </item> 
    </xsl:template> 
</xsl:transform> 

Хотя это, вероятно, не чистит, так что вы должны скорее оставить заказ, как это было и явно установить ПРИО~D выше чем .5 к более специализированному шаблону вместо:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="/root"> 
     <output> 
      <xsl:apply-templates select="outer[@type='foo']/inner"/> 
     </output> 
    </xsl:template> 
    <xsl:template match="outer[@type='foo']/inner[@type='bar1' or @type='bar2' or @type='bar3' or @type='bar4']" priority="1"> 
     <item> 
      <xsl:value-of select="text()"/> 
     </item> 
    </xsl:template> 
    <xsl:template match="outer[@type='foo']/inner"> 
     <xsl:message terminate="yes"> 
      <xsl:value-of select="concat('Unexpected type: ', @type)"/> 
     </xsl:message> 
    </xsl:template> 
</xsl:transform> 
+0

Явное определение приоритета кажется самым чистым исправлением, спасибо! – flyx

1

Обе ваши согласующих выражения имеют приоритет .5 согласно http://lenzconsulting.com/how-xslt-works/#priority

Так что ваши шаблоны противоречивы. Как насчет обработки всего в одном шаблоне?

<xsl:template match="outer[@type='foo']/inner"> 
    <xsl:choose> 
     <xsl:when test="@type='bar1' or @type='bar2' or @type='bar3' or @type='bar4'"> 
      <item> 
       <xsl:value-of select="text()"/> 
      </item> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:message terminate="yes"> 
       <xsl:value-of select="concat('Unexpected type: ', @type)"/> 
      </xsl:message> 
     </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 
+1

Найдено несколько больше в этой статье я, указанной выше: «это ошибка, если есть более чем одно правило шаблона влево Если это произойдет, то XSLT проц. ssor может либо сигнализировать об ошибке, либо восстанавливать, вызывая соответствующее правило шаблона, которое встречается последним в таблице стилей. Большинство процессоров, по крайней мере, дадут предупреждение, если это произойдет ». Таким образом, ваш XSLT-процессор (мой тоже, BTW!) Принадлежит тем, которые не дают предупреждения, и просто используют * последний шаблон соответствия в файле. –

+0

Это определенно лучше использовать явные приоритеты.Если вы этого не сделаете, то и XSLT 1.0, и 2.0 говорят, что это ошибка, которую процессор может сообщить или восстановить, выбирая последнее правило. XSLT 3.0 делает «последнее правило выигрывает» "поведение обязательное, если вы не укажете' ' –