Результаты XPath из XSLT неверны - не проходит через весь XML - PullRequest
1 голос
/ 10 августа 2010

Итак, у меня действительно запутанная проблема на руках ..

При использовании выражения XPath в XSL создается впечатление, что вся иерархия данных XML не просматривается.

Некоторые фиктивные данные XML:

<pets name="myPets" NUM="2">
    <dog name="allMyDogs" NUM="5">
        <dog name="Frank"  NUM="3"/>
        <dog name="Spot"  NUM="4"/>
        <dog name="Rover"  NUM="1"/>
        <dog name="Rupert" NUM="6"/>
        <cat name="Lucy"  NUM="4"/>
    </dog>
    <cat name="allMyCats" NUM="4">
        <cat name="Simba" NUM="4"/>
        <cat name="Princess"  NUM="5"/>
        <cat name="Fluffy" NUM="1"/>
        <cat name="Lucy"  NUM="3"/>
        <cat name="Lucy"  NUM="35"/>
        <cat name="Lucy"  NUM="6"/>
        <cat name="Lucy" NUM="1"/>
    </cat>
    <cat name="Lucy" NUM="9"/>
</pets>

Ниже приведен фрагмент кода XSLT, который, по моему мнению, вызывает проблему:

 <xsl:key name="elem_key" match="elem" use="concat(@key, .)" />

  <xsl:variable name="all_data">
    <xsl:apply-templates select="*">
      <xsl:sort select="name()" />
    </xsl:apply-templates>
  </xsl:variable>

  <xsl:template match="//*[@NUM&lt;=4]">
    <elem key="{name()}">
      <xsl:copy-of select="@*" />
      <xsl:for-each select="@*">
        <xsl:sort select="name()" />
        <attribute>|<xsl:value-of select="name()" />|</attribute>
      </xsl:for-each>
    </elem>
  </xsl:template>

  <xsl:template match="/">
    <html>
      <body>
        <xsl:for-each select="msxsl:node-set($all_data)">
              <xsl:for-each select="*[generate-id()=generate-id(key('elem_key',concat(@key, .))[1])]">
                <table >
                  <tr>
                    <td>Element Name</td>
                    <xsl:for-each select="*">
                      <td>
                        <xsl:value-of select="translate(.,'|','')" />
                      </td>
                    </xsl:for-each>
                  </tr>
                  <xsl:for-each select="key('elem_key', concat(@key, .))">
                    <xsl:variable name="curr_elem" select="." />
                    <tr>
                      <td>
                        <xsl:value-of select="@key" />
                      </td>
                      <xsl:for-each select="*">
                        <td >
                          <xsl:value-of select="$curr_elem/@*[name()=translate(current(),'|','')]" />
                        </td>
                      </xsl:for-each>
                    </tr>
                  </xsl:for-each>
                </table>
                <p />
              </xsl:for-each>
        </xsl:for-each>
      </body>
    </html>
  </xsl:template>

Используемое выражение XPath:

//*[@NUM&lt;=4]

(выше должно генерировать много результатов)

Неверные результаты, которые я получаю:

Element Name    name     NUM
pets            myPets   2

Как вы можете видеть, он, кажется, останавливается на корне.

Если я изменю XPath на:

//*[@NUM=4]

Я получаю неправильные результаты:

Element Name  name    NUM
dog        Spot      4


Element Name  name      NUM
cat        Lucy      4


Element Name  name      NUM
cat        allMyCats   4

Похоже, что происходит, что он прекратит поиск в иерархии, как только найдет совпадение. Первые два (Spot и Lucy) верны, но затем остановились на allMyCats, когда есть дочерний узел allMyCats (Simba), имеющий NUM 4.

Может кто-нибудь помочь мне исправить этот код, чтобы он возвращал правильные результаты? Я очень расстроен! (

Спасибо!

Ответы [ 2 ]

3 голосов
/ 11 августа 2010

Просто измените :

  <xsl:variable name="all_data">
    <xsl:apply-templates select="*">
      <xsl:sort select="name()" />
    </xsl:apply-templates>
  </xsl:variable>

На :

  <xsl:variable name="all_data">
    <xsl:apply-templates select="*/*">
      <xsl:sort select="name()" />
    </xsl:apply-templates>
  </xsl:variable>

Первая (из многих) проблема :

<xsl:apply-templates select="*">

выбирает все дочерние элементы текущего узла.Текущий узел - /, и у него есть только один дочерний элемент - верхний элемент pets.

Вы действительно хотите собрать данные для всех дочерних элементов pets.

Есть и другие проблемы, но у меня нет места и времени для их решения.

Полный исправленный код приведен ниже :

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:msxsl="urn:schemas-microsoft-com:xslt"
version="1.0">

 <xsl:key name="elem_key" match="elem" 
      use="concat(@key, .)" />

  <xsl:variable name="all_data">
    <xsl:apply-templates select="*//*">
      <xsl:sort select="name()" />
    </xsl:apply-templates>
  </xsl:variable>

  <xsl:template match="*[@NUM&lt;=4]">
    <elem key="{name()}">
      <xsl:copy-of select="@*" />
      <xsl:for-each select="@*">
        <xsl:sort select="name()" />
        <attribute>|<xsl:value-of 
             select="concat(name(),'=',.)" />|</attribute>
      </xsl:for-each>
    </elem>
  </xsl:template>

  <xsl:template match="/">
    <html>
      <body>
        <xsl:for-each select="msxsl:node-set($all_data)">
              <xsl:for-each select=
               "*[generate-id()
                 =
                  generate-id(key('elem_key',concat(@key, .))[1])
                 ]">
                <table >
                  <tr>
                    <td>Element Name</td>
                    <xsl:for-each select="*">
                      <td>
                        <xsl:value-of select=
                          "substring-before(translate(.,'|',''),'=')" />
                      </td>
                    </xsl:for-each>
                  </tr>
                    <tr>
                      <td>
                        <xsl:value-of select="@key" />
                      </td>
                      <xsl:for-each select="*">
                        <td>
                          <xsl:value-of select=
                          "substring-after
                              (translate(current(),'|',''),
                               '='
                               )"/>
                        </td>
                      </xsl:for-each>
                    </tr>
                </table>
                <p />
              </xsl:for-each>
        </xsl:for-each>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>

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

<pets name="myPets" NUM="2">
    <dog name="allMyDogs" NUM="5">
        <dog name="Frank"  NUM="3"/>
        <dog name="Spot"  NUM="4"/>
        <dog name="Rover"  NUM="1"/>
        <dog name="Rupert" NUM="6"/>
        <cat name="Lucy"  NUM="4"/>
    </dog>
    <cat name="allMyCats" NUM="4">
        <cat name="Simba" NUM="4"/>
        <cat name="Princess"  NUM="5"/>
        <cat name="Fluffy" NUM="1"/>
        <cat name="Lucy"  NUM="3"/>
        <cat name="Lucy"  NUM="35"/>
        <cat name="Lucy"  NUM="6"/>
        <cat name="Lucy" NUM="1"/>
    </cat>
    <cat name="Lucy" NUM="9"/>
</pets>

желаемый результат (несколько животных) получается :

<html xmlns:msxsl="urn:schemas-microsoft-com:xslt">
    <body>
        <table>
            <tr>
                <td>Element Name</td>
                <td>name</td>
                <td>NUM</td>
            </tr>
            <tr>
                <td>cat</td>
                <td>Lucy</td>
                <td>4</td>
            </tr>
        </table>
        <p></p>
        <table>
            <tr>
                <td>Element Name</td>
                <td>name</td>
                <td>NUM</td>
            </tr>
            <tr>
                <td>cat</td>
                <td>allMyCats</td>
                <td>4</td>
            </tr>
        </table>
        <p></p>
        <table>
            <tr>
                <td>Element Name</td>
                <td>name</td>
                <td>NUM</td>
            </tr>
            <tr>
                <td>cat</td>
                <td>Simba</td>
                <td>4</td>
            </tr>
        </table>
        <p></p>
        <table>
            <tr>
                <td>Element Name</td>
                <td>name</td>
                <td>NUM</td>
            </tr>
            <tr>
                <td>cat</td>
                <td>Fluffy</td>
                <td>1</td>
            </tr>
        </table>
        <p></p>
        <table>
            <tr>
                <td>Element Name</td>
                <td>name</td>
                <td>NUM</td>
            </tr>
            <tr>
                <td>cat</td>
                <td>Lucy</td>
                <td>3</td>
            </tr>
        </table>
        <p></p>
        <table>
            <tr>
                <td>Element Name</td>
                <td>name</td>
                <td>NUM</td>
            </tr>
            <tr>
                <td>cat</td>
                <td>Lucy</td>
                <td>1</td>
            </tr>
        </table>
        <p></p>
        <table>
            <tr>
                <td>Element Name</td>
                <td>name</td>
                <td>NUM</td>
            </tr>
            <tr>
                <td>dog</td>
                <td>Frank</td>
                <td>3</td>
            </tr>
        </table>
        <p></p>
        <table>
            <tr>
                <td>Element Name</td>
                <td>name</td>
                <td>NUM</td>
            </tr>
            <tr>
                <td>dog</td>
                <td>Spot</td>
                <td>4</td>
            </tr>
        </table>
        <p></p>
        <table>
            <tr>
                <td>Element Name</td>
                <td>name</td>
                <td>NUM</td>
            </tr>
            <tr>
                <td>dog</td>
                <td>Rover</td>
                <td>1</td>
            </tr>
        </table>
        <p></p>
    </body>
</html>
0 голосов
/ 10 августа 2010

*[generate-id()=generate-id(key('elem_key',concat(@key, .))[1])] У вас есть ключ, делающий выбор, который соответствует нескольким случаям, а затем вы запрашиваете только первое с [1]

Мне непонятно, какой макет вы хотите получить в качестве правильных результатов, чтобы посоветовать дальше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...