Как пройти несколько наборов узлов параллельно, используя XSL? - PullRequest
2 голосов
/ 23 марта 2012

Мне интересно, есть ли способ, позволяющий выполнять итерацию по документу XML и двум наборам его узлов одновременно, я понимаю, что это не очень описательный вопрос, поэтому вот пример:

Пример xml:

<document>
  <animal species="dog">
    <fact>4 legs</fact>
    <fact>2 eyes</fact>
    <fact>loyal</fact>
  </animal>
  <animal species="horse">
    <fact>rideable</fact>
    <fact>4 legs</fact>
    <fact>2 eyes</fact>
    <fact>huge</fact>
  </animal>
</document>

xsl, нуждающийся в редактировании:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
  <html>
  <body>
  <h2>Results</h2>
  <table border="1">
    <tr bgcolor="#9acd32">
      <th>Dogs</th>
      <th>Horses</th>
    </tr>
    <xsl:for-each select="document">
      <???for all greater quantity of facts between the 2 in this document>
        <tr>
          <td><xsl:value-of select="./animal/@dog/fact[current#]"/></td>
          <td><xsl:value-of select="./animal/@horse/fact[current#]"/></td>
        </tr>
      </???>
    </xsl:for-each>
  </table>
  </body>
  </html>
</xsl:template>
</xsl:stylesheet>

Что именно я должен заменить ???метод с, чтобы получить таблицу по следующему?

Dogs   |Horses   | 
4 legs |rideable |
2 eyes |4 legs   |
loyal  |2 eyes   |

Любая возможная помощь приветствуется.

Ответы [ 3 ]

0 голосов
/ 23 марта 2012

Мое решение для XSLT 1.0 и работает под управлением Altova XMLSpy. Следующий шаблон:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
  <html>
  <body>
  <h2>Results</h2>
  <table border="1">
    <tr bgcolor="#9acd32">
      <th>Dogs</th>
      <th>Horses</th>
    </tr>
    <xsl:apply-templates select="document">
        <xsl:with-param name="num" select="1" />
    </xsl:apply-templates>
  </table>
  </body>
  </html>
</xsl:template>
<xsl:template match="document">
<xsl:param name="num" />
    <xsl:if test="count(animal/fact[$num]) = count(animal)">
        <tr>
            <xsl:for-each select="animal">
              <td><xsl:value-of select="fact[$num]"/></td>
            </xsl:for-each>
        </tr>
        <xsl:apply-templates select=".">
            <xsl:with-param name="num" select="$num + 1"/>
        </xsl:apply-templates>
    </xsl:if>
</xsl:template>
</xsl:stylesheet>

, примененный к предоставленному входному XML, дает следующий результат:

<html>
    <body>
        <h2>Results</h2>
        <table border="1">
            <tr bgcolor="#9acd32">
                <th>Dogs</th>
                <th>Horses</th>
            </tr>
            <tr>
                <td>4 legs</td>
                <td>rideable</td>
            </tr>
            <tr>
                <td>2 eyes</td>
                <td>4 legs</td>
            </tr>
            <tr>
                <td>loyal</td>
                <td>2 eyes</td>
            </tr>
        </table>
    </body>
</html>

Я предположил, что вас не интересует генерация строк, в которых будет заполнена только одна ячейка (последняя строка, которая будет иметь только значение huge в столбце Horse, не должна приниматься во внимание). Это отличается от решения Дэвида.

РЕДАКТИРОВАТЬ: Однако, действительно просто изменить мой подход, чтобы получить те же результаты, что и Дэвид Требуется только изменить условие при вызове функции count() XPATH:

<xsl:if test="count(animal/fact[$num]) > 0">

вместо:

<xsl:if test="count(animal/fact[$num]) = count(animal)">

Сделав это, вы получите следующий вывод:

<html>
    <body>
        <h2>Results</h2>
        <table border="1">
            <tr bgcolor="#9acd32">
                <th>Dogs</th>
                <th>Horses</th>
            </tr>
            <tr>
                <td>4 legs</td>
                <td>rideable</td>
            </tr>
            <tr>
                <td>2 eyes</td>
                <td>4 legs</td>
            </tr>
            <tr>
                <td>loyal</td>
                <td>2 eyes</td>
            </tr>
            <tr>
                <td></td>
                <td>huge</td>
            </tr>
        </table>
    </body>
</html>
0 голосов
/ 23 марта 2012

Вот общее решение XSLT 1.0, которое работает правильно, если любое количество животных может присутствовать в документе XML. Никакие названия видов не имеют жесткого кода :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:variable name="vHavingMaxFactsPosition">
  <xsl:for-each select="/*/animal">
   <xsl:sort select="count(*)" data-type="number"
        order="descending"/>
   <xsl:if test="position() = 1">
    <xsl:value-of select="count(preceding-sibling::animal)+1"/>
   </xsl:if>
  </xsl:for-each>
 </xsl:variable>

 <xsl:variable name="vHavingMaxFacts" select=
   "/*/*[position() = $vHavingMaxFactsPosition]"/>

 <xsl:template match="/*">
  <html>
   <body>
     <table border="1">
       <tr>
         <xsl:apply-templates select="*/@species"/>
       </tr>
       <xsl:apply-templates mode="startRow" select="$vHavingMaxFacts/*"/>
     </table>
   </body>
  </html>
 </xsl:template>

 <xsl:template match="fact" mode="startRow">
  <xsl:variable name="vPos" select="position()"/>

  <tr>
   <xsl:for-each select="/*/*">
    <td><xsl:value-of select="*[position()=$vPos]"/></td>
   </xsl:for-each>
  </tr>
 </xsl:template>

 <xsl:template match="@species">
  <th><xsl:value-of select="."/></th>
 </xsl:template>
</xsl:stylesheet>

При применении к предоставленному документу XML :

<document>
    <animal species="dog">
        <fact>4 legs</fact>
        <fact>2 eyes</fact>
        <fact>loyal</fact>
    </animal>
    <animal species="horse">
        <fact>rideable</fact>
        <fact>4 legs</fact>
        <fact>2 eyes</fact>
        <fact>huge</fact>
    </animal>
</document>

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

<html>
   <body>
      <table border="1">
         <tr>
            <th>dog</th>
            <th>horse</th>
         </tr>
         <tr>
            <td>4 legs</td>
            <td>rideable</td>
         </tr>
         <tr>
            <td>2 eyes</td>
            <td>4 legs</td>
         </tr>
         <tr>
            <td>loyal</td>
            <td>2 eyes</td>
         </tr>
         <tr>
            <td></td>
            <td>huge</td>
         </tr>
      </table>
   </body>
</html>

Когда то же преобразование , примененное выше к этому XML-документу (3 животных - паук с добавлением 5 фактов):

<document>
    <animal species="dog">
        <fact>4 legs</fact>
        <fact>2 eyes</fact>
        <fact>loyal</fact>
    </animal>
    <animal species="horse">
        <fact>rideable</fact>
        <fact>4 legs</fact>
        <fact>2 eyes</fact>
        <fact>huge</fact>
    </animal>
    <animal species="spider">
        <fact>insect</fact>
        <fact>6 legs</fact>
        <fact>x eyes</fact>
        <fact>small</fact>
        <fact>dangerous</fact>
    </animal>
</document>

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

<html>
   <body>
      <table border="1">
         <tr>
            <th>dog</th>
            <th>horse</th>
            <th>spider</th>
         </tr>
         <tr>
            <td>4 legs</td>
            <td>rideable</td>
            <td>insect</td>
         </tr>
         <tr>
            <td>2 eyes</td>
            <td>4 legs</td>
            <td>6 legs</td>
         </tr>
         <tr>
            <td>loyal</td>
            <td>2 eyes</td>
            <td>x eyes</td>
         </tr>
         <tr>
            <td></td>
            <td>huge</td>
            <td>small</td>
         </tr>
         <tr>
            <td></td>
            <td></td>
            <td>dangerous</td>
         </tr>
      </table>
   </body>
</html>
0 голосов
/ 23 марта 2012

Как обычно, если вы застряли в XSLT1 и не можете использовать xsl: for-each-group, вы хотите использовать группировку muenchian

<html>
   <body>
      <h2>Results</h2>
      <table border="1">
         <tr bgcolor="#9acd32">
            <th>Dogs</th>
            <th>Horses</th>
         </tr>
         <tr>
            <td>4 legs</td>
            <td>rideable</td>
         </tr>
         <tr>
            <td>2 eyes</td>
            <td>4 legs</td>
         </tr>
         <tr>
            <td>loyal</td>
            <td>2 eyes</td>
         </tr>
         <tr>
            <td></td>
            <td>huge</td>
         </tr>
      </table>
   </body>
</html>

из этого xslt

 -  <xsl:stylesheet version="1.0"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
       <xsl:template match="/">
        <html>
         <body>
          <h2>Results</h2>
          <table border="1">
           <tr bgcolor="#9acd32">
            <th>Dogs</th>
            <th>Horses</th>
           </tr>
           <xsl:for-each select="document">
            <xsl:for-each select="animal/fact[generate-id()=generate-id(key('f',1+count(preceding-sibling::fact))[1])]">
             <tr>
              <xsl:variable name="k"  select="key('f',1+count(preceding-sibling::fact))"/>
              <td><xsl:value-of select="$k[../@species='dog']"/></td>
              <td><xsl:value-of select="$k[../@species='horse']"/></td>
             </tr>
            </xsl:for-each>
           </xsl:for-each>
          </table>
         </body>
        </html>
       </xsl:template>
       <xsl:key name="f" match="fact" use="1+count(preceding-sibling::fact)"/>
       </xsl:stylesheet>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...