2012-02-24 4 views
2

У меня есть XML, как это:Не удается получить правильный вывод XSLT

<?xml version="1.0" encoding="UTF-8"?> 
<Section> 
    <Chapter> 
     <nametable> 
      <namerow> 
       <namecell stuff="1"> 
        <entity>A</entity> 
       </namecell> 
       <namecell stuff="2"> 
        <entity>B</entity> 
       </namecell> 
      </namerow> 
     </nametable> 
    </Chapter> 
</Section> 

Мой XSLT, как это:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="2.0"> 

<xsl:output method="text"/> 

    <xsl:template match="/"> 
     <xsl:apply-templates select="Section/Chapter//nametable"/> 
    </xsl:template> 

    <xsl:template match="nametable"> 
     <xsl:for-each select="./namerow"> 
      <xsl:value-of select="./namecell/@stuff"/> 
      <xsl:value-of select="./namecell" /> 
     </xsl:for-each> 
    </xsl:template> 

<xsl:template match="text()"/> 

</xsl:stylesheet> 

Чет я получаю выход в таком порядке 1 2 А. Б., я думал, что собираюсь получить 1 A 2 B.

Не знаете, почему это?.

ТИА,

Джон

ответ

3

Ваша проблема здесь:

 <xsl:for-each select="./namerow"> 
      <xsl:value-of select="./namecell/@stuff"/> 
      <xsl:value-of select="./namecell" /> 
     </xsl:for-each> 

В отличие от XSLT 1.0 в XSLT 2.0 xsl:value-of команд выводит все элементы последовательности, указанной в атрибуте select.

Это означает, что

<xsl:value-of select="./namecell/@stuff"/> 

выводит все атрибуты stuff (1 и 2)

то следующая инструкция:

  <xsl:value-of select="./namecell" /> 

выводит значение строки из двух namecell детей - соответственно "A" и "B".

Решение:

Заменить:

 <xsl:for-each select="./namerow"> 
      <xsl:value-of select="./namecell/@stuff"/> 
      <xsl:value-of select="./namecell" /> 
     </xsl:for-each> 

с:

 <xsl:for-each select="./namerow"> 
      <xsl:value-of select="./namecell/(@stuff|entity)"/> 
     </xsl:for-each> 

Полный код этой модификации:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
     version="2.0"> 

    <xsl:output method="text"/> 

     <xsl:template match="/"> 
      <xsl:apply-templates select="Section/Chapter//nametable"/> 
     </xsl:template> 

     <xsl:template match="nametable"> 
      <xsl:for-each select="./namerow"> 
       <xsl:value-of select="./namecell/(@stuff|entity)"/> 
      </xsl:for-each> 
     </xsl:template> 

    <xsl:template match="text()"/> 
</xsl:stylesheet> 

и когда это преобразование применяется на поставленном XML документа:

<Section> 
    <Chapter> 
     <nametable> 
      <namerow> 
       <namecell stuff="1"> 
        <entity>A</entity> 
       </namecell> 
       <namecell stuff="2"> 
        <entity>B</entity> 
       </namecell> 
      </namerow> 
     </nametable> 
    </Chapter> 
</Section> 

разыскиваемый результат получают:

1 A 2 B 

Второе решение (вероятно, что вы намеревались сделать в первую очередь):

Заменить:

<xsl:template match="nametable"> 
     <xsl:for-each select="./namerow"> 
      <xsl:value-of select="./namecell/@stuff"/> 
      <xsl:value-of select="./namecell" /> 
     </xsl:for-each> 
    </xsl:template> 

с:

<xsl:template match="nametable"> 
     <xsl:for-each select="namerow/namecell"> 
      <xsl:value-of select="@stuff"/> 
      <xsl:value-of select="entity"/> 
     </xsl:for-each> 
    </xsl:template> 

Теперь вы снова получить нужный результат:

1A2B 
+0

oh! Вот ответ :) +1 –

+0

Dimitri: Что это за действительно делать?. – JohnX

+0

@JohnX: '' выводит как текстовые узлы строковые значения каждого атрибута 'stuff' и' entity' child каждого 'namecell 'child текущего узла. Здесь я использую Xpath * union * operator '|'. Такой союз на этапе местоположения возможен только в XPath 2.0 - синтаксически незаконно в XPath 1.0. –

1

Я использую MSXML, я получаю 1 A, как оп: |

Ну вот это решение для вас это работает, как драгоценный камень :)

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="2.0"> 

    <xsl:output method="text"/> 

    <xsl:template match="/Section/Chapter/nametable/namerow/namecell"> 
    <xsl:value-of select="@stuff"/> 
    <xsl:text> </xsl:text><!--inserting a space--> 
    <xsl:value-of select="entity"/> 
    <xsl:text> </xsl:text><!--inserting a space--> 
    </xsl:template> 
    <xsl:template match="text()"/> 

</xsl:stylesheet> 
+0

Вот что я сделал, чтобы получить Corre Ответ ct, я использую Saxon EE, но я не понимаю, почему мой оригинальный пост не работает так, как он должен был. – JohnX

+0

Это может быть потому, что вы используете '/ namecell/@ stuff' вместо'/@ stuff'. Я не очень сфокусирован на xslt 2.0, поэтому не уверен. –

+0

Пожалуйста, обратитесь к ответу Димитрия. –

1

Причина поведения вы видите, что вы перебрать namerow. Вы получите 1A2B, если вместо этого вы будете перебирать namecell как: <xsl:for-each select="namerow/namecell"><xsl:value-of select="@stuff"/><xsl:value-of select="." /></xsl:for-each>. Вы хотите помнить, что каждый XPath, такой как @stuff, дает вам не обязательно одно значение (узел), а набор значений (набор узлов). Обычно этот набор содержит только одно значение, но не обманывается.

Другой синтаксис для одного и того же: <xsl:for-each select="namerow"><xsl:for-each select="namecell"><xsl:value-of select="@stuff"/><xsl:value-of select="." /></xsl:for-each></xsl:for-each>

P.S. Как и в пути к файловой системе, вам не нужно писать «./» перед XPath.

+0

Сделать смысл. Спасибо !. – JohnX