XSLT1.0 Рендеринг последовательности различных элементов, хранящихся в переменной в виде таблицы M x N - PullRequest
1 голос
/ 08 июня 2010

У меня есть следующий XML (он упрощен и большинство атрибутов опущено):

<Document>
  <Transfer Name="" From="" To=""/>
  <Transfer Name="" From="" To=""/>
  <OtherElement/>
  <OtherElement/>
  <Flight AirLina="" From="" To=""/>
  <Flight AirLina="" From="" To=""/>
  <OtherElement/>
  <Hotel Name="" Duration=""/>
  <Hotel Name="" Duration=""/>
  <OtherElement/>
  <OtherElement/>
  <Extras Name="" Price=""/>
  <Extras Name="" Price=""/>
  <Extras Name="" Price=""/>
  <Extras Name="" Price=""/>
  <Extras Name="" Price=""/>
  <Extras Name="" Price=""/>
  <OtherElement/>
  <OtherElement/>
</Document>

У меня есть переменная, содержащая различные элементы:

<xsl:variable name="packageElements" 
select="/Document/Transfer | /Document/Coach | /Document/Flight | /Document/Hotel | /Document/Extras" />

Я хотел бы отобразить эти данные в таблице с двумя столбцами. Я использую XSLT1.0 и процессор MSXSL.

Я пробовал это с самым простым решением, которое я мог придумать:

<table>
  <tbody>
    <xsl:for-each select="$packageElements[position() mod 2 = 1]">
      <tr>
        <td>
          <!-- current element -->
          <xsl:value-of select="local-name()"/>
        </td>
        <td>
          <!-- element following the current in the $packageElements variable -->
          <!-- Here is where I'm stuck, I can't figure out how to correctly pick it up :( -->
        </td>
      </tr>
    </xsl:for-each>
  </tbody>
</table>

Был бы очень признателен за любую помощь.

Ответы [ 3 ]

1 голос
/ 08 июня 2010

Это преобразование :

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

 <xsl:variable name="vData" select="/*/*"/>

 <xsl:template match="/">
  <table border="1">
    <xsl:apply-templates select="$vData[position() mod 2 = 1]"/>
  </table>
 </xsl:template>

 <xsl:template match="nums/*">
  <xsl:variable name="vPos" select="position()"/>

  <tr>
    <td><xsl:value-of select="name()"/></td>
    <td><xsl:value-of select="$vData[position() = 2*$vPos]"/></td>
  </tr>
 </xsl:template>
</xsl:stylesheet>

при применении к этому документу XML :

<nums>
  <A>01</A>
  <num>02</num>
  <B>03</B>
  <num>04</num>
  <C>05</C>
  <num>06</num>
  <D>07</D>
  <num>08</num>
  <E>09</E>
  <num>010</num>
</nums>

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

<table border="1">
    <tr>
        <td>A</td>
        <td>02</td>
    </tr>
    <tr>
        <td>B</td>
        <td>04</td>
    </tr>
    <tr>
        <td>C</td>
        <td>06</td>
    </tr>
    <tr>
        <td>D</td>
        <td>08</td>
    </tr>
    <tr>
        <td>E</td>
        <td>010</td>
    </tr>
</table>
1 голос
/ 09 июня 2010

Хорошо

Я объединил идею @Dimitre Novatchev из ответов этого поста и @ Tomalak из [XSLT]: рендеринг последовательности узлов в виде таблицы M x N post. Мне очень понравилось решение @ Tomalak с переменной $perRow и шаблон <xsl:template name="filler"> для работы с пустыми ячейками.

С идеей, взятой из ответа @Dimitre Novatchev, я держусь за $trStartPos. Затем я вычисляю $lowerBoundry и $upperBoundry, которые используются для накопления всех элементов, которые должны появиться в строке. Может быть, есть более элегантный способ сделать этот расчет - пожалуйста, дайте мне знать, если вы придумали один, я был бы очень признателен!

XSLT-преобразование

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

<!-- Select only required elements -->
<xsl:variable name="tableData" 
     select="/nums/A | /nums/B | /nums/C | /nums/D | /nums/E "/>
<xsl:variable name="perRow" select="2"/>

<xsl:template match="/">
    <table border="1">
        <tbody>
            <xsl:apply-templates 
                select="$tableData[position() mod $perRow = 1]" mode="tr"/>
        </tbody>            
    </table>
</xsl:template>


<xsl:template match="nums/*" mode="tr">
    <xsl:variable name="trStartPos" select="position()" />
    <xsl:variable name="upperBoundry" select="$trStartPos * $perRow" />
    <xsl:variable name="lowerBoundry" select="$upperBoundry - $perRow" />

    <tr>
        <xsl:variable name="tdsData" 
            select="$tableData[(position() &gt; $lowerBoundry) and (position() &lt;= $upperBoundry)]" />
        <xsl:apply-templates select="$tdsData" mode="td"/>
        <!-- fill up the last row - @Tomalak's solution -->
        <xsl:if test="count($tdsData) &lt; $perRow">
            <xsl:call-template name="filler">
                <xsl:with-param name="rest" select="$perRow - count($tdsData)" />
            </xsl:call-template>
        </xsl:if>
    </tr>
</xsl:template>


<!-- Templates for specific elements could be easily added with appropriate info to
     be displayed depending on the element. This one is general just to display
     elements' name and value -->
<xsl:template match="nums/*" mode="td">
    <td>
        El. name: <xsl:value-of select="local-name()"/> -
        El. value: <xsl:value-of select="."/>
    </td>
</xsl:template>

<!-- @Tomalak solution (please read beginning of this answer for reference) -->
<xsl:template name="filler">
    <xsl:param name="rest" select="0" />
    <xsl:if test="$rest">
        <td>&#160;</td>
        <xsl:call-template name="filler">
            <xsl:with-param name="rest" select="$rest - 1" />
        </xsl:call-template>
    </xsl:if>
</xsl:template>
</xsl:stylesheet>

применяется к следующему XML

<nums>
  <A>A-01</A>
  <num>02</num>
  <num>03</num>
  <num>04</num>
  <B>B-05</B>
  <num>06</num>
  <num>07</num>
  <C>C-08</C>
  <num>09</num>
  <D>D-10</D>
  <num>11</num>
  <num>12</num>
  <num>13</num>
  <E>E-14</E>
  <num>15</num>
</nums>

приводит к следующему выводу

<table border="1">
    <tbody>
        <tr>
            <td>
                El. name: A -
                El. value: A-01
            </td>
            <td>
                El. name: B -
                El. value: B-05
            </td>
        </tr>
        <tr>
            <td>
                El. name: C -
                El. value: C-08
            </td>
            <td>
                El. name: D -
                El. value: D-10
            </td>
        </tr>
        <tr>
            <td>
                El. name: E -
                El. value: E-14
            </td>
            <td> </td>
        </tr>
    </tbody>
</table>
1 голос
/ 08 июня 2010

Я думаю, что здесь есть сложность:

элемент после текущего в переменной $ packageElements

Это узел в $Пакетный узел packageElements с позицией () больше, чем текущий узел.Но какова позиция текущего узла в наборе узлов $ packegeElements ?

Проверьте this .Dimitre создает выражение, которое является счетчиком пересечения между предыдущими узлами (в документе) текущего узла и набора узлов.

...