如何在XSLT中使用position()进行循环

时间:2014-11-16 22:02:21

标签: xml xslt

我是XSLT的新手,我有一个像这样的XML;

<TerminalRoutes>
        <Segment>
            <From>
                <previous>DEN </previous>
                <current>DNV</current>
            </From>
            <From>
                <previous>LAX </previous>
                <current>LAS</current>
            </From>
        </Segment>
        <Segment>
            <To>
                <previous>ATL </previous>
                <current>ATN</current>
            </To>
            <To>
                <previous>JFK</previous>
                <current>LGA </current>
            </To>
        </Segment>
 </TerminalRoutes>

我正在尝试使用XSLT将XML转换为HTML,并且我正在应用此模板

<xsl:template match="TerminalRoutes">
            <tr>
                <td>
                    <b>Terminal Routes</b>
                </td>
                <td>&#160;</td>
                <td>&#160;</td>
            </tr>
            <tr>

            <td>TERMINAL ROUTES FROM</td>
                <td>
                    <xsl:value-of select="Segment/From/previous"></xsl:value-of>
                </td>
                <td>
                    <xsl:value-of select="Segment/From/current"></xsl:value-of>
                </td>
            </tr>
            <tr>
            <td>TERMINAL ROUTES TO</td>
                <td>
                    <xsl:value-of select="Segment/To/previous"></xsl:value-of>
                </td>
                <td>
                    <xsl:value-of select="Segment/To/current"></xsl:value-of>
                </td>
            </tr>
        </xsl:template>

并且得到的HTML给了我第一个结果集,即第一个&#34; From&#34;和第一个&#34; To&#34;。

我想要的是重新应用相同的模板,因此我可以捕获第二个结果集,即第二个&#34; From&#34;第二个&#34; To&#34;。我相信有一个position()函数可以使用,但我不确定如何。

2 个答案:

答案 0 :(得分:1)

试试这个:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:msxsl="urn:schemas-microsoft-com:xslt"
  exclude-result-prefixes="msxsl"

>

  <xsl:output method="html" encoding="UTF-8" indent="yes" />
  <xsl:template match="TerminalRoutes">
    <tr>
      <td>
        <b>Terminal Routes</b>
      </td>
      <td>&#160;</td>
      <td>&#160;</td>
    </tr>
    <xsl:apply-templates select=".//*" />
  </xsl:template>

  <xsl:template match="/TerminalRoutes/Segment/From">
    <tr>
      <td>TERMINAL ROUTES FROM</td>
      <td>
        <xsl:value-of select="./previous"></xsl:value-of>
      </td>
      <td>
        <xsl:value-of select="./current"></xsl:value-of>
      </td>
    </tr>
    <tr>
      <td>TERMINAL ROUTES TO</td>
      <td>
        <xsl:value-of select="../../Segment/To[1 + count(preceding-sibling::*)]/previous"></xsl:value-of>
      </td>
      <td>
        <xsl:value-of select="../../Segment/To[1 + count(preceding-sibling::*)]/current"></xsl:value-of>
      </td>
    </tr>
  </xsl:template>

  <xsl:template match="*" />

</xsl:stylesheet>

1 + count(preceding-sibling::*)通过计算其前面的数字(NB:索引从1开始,而不是XML技术中的0),为您提供当前FROM元素与其兄弟节点相比的索引。 然后,我们使用此数字来指定我们希望To元素与我们当前匹配的From元素具有相同的索引。

注意:尽管上述解决方案有效,但如果可能,我建议采用更好的方法:重构源XML以更好地分组数据;即将相关的FROM和TO值放在同一个父级下,这样数据结构就意味着这种关系,使得阅读,验证和使用起来更加简单。

e.g。

<TerminalRoutes>
  <Route>
    <From>
      <previous>DEN </previous>
      <current>DNV</current>
    </From>
    <To>
      <previous>ATL </previous>
      <current>ATN</current>
    </To>
  </Route>
  <Route>
    <From>
      <previous>LAX </previous>
      <current>LAS</current>
    </From>
    <To>
      <previous>JFK</previous>
      <current>LGA </current>
    </To>
  </Route>
</TerminalRoutes>

答案 1 :(得分:0)

就像position()循环中for-each的使用方式一样:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>

<xsl:template match="TerminalRoutes">
<table>
<xsl:for-each select="Segment/From">
<xsl:variable name="position" select="position()"/>
  <tr>
    <td>
      <b>Terminal Routes</b>
    </td>
    <td>&#160;</td>
    <td>&#160;</td>
  </tr>
  <tr>
    <td>TERMINAL ROUTES FROM</td>
    <td>
      <xsl:value-of select="previous"></xsl:value-of>
    </td>
    <td>
      <xsl:value-of select="current"></xsl:value-of>
    </td>
  </tr>
  <tr>
    <td>TERMINAL ROUTES TO</td>
    <td>
      <xsl:value-of select="//Segment/To[$position]/previous"></xsl:value-of>
    </td>
    <td>
      <xsl:value-of select="//Segment/To[$position]/current"></xsl:value-of>
    </td>
  </tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>

输出:

<table>
  <tr>
    <td><b>Terminal Routes</b></td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <td>TERMINAL ROUTES FROM</td>
    <td>DEN </td>
    <td>DNV</td>
  </tr>
  <tr>
    <td>TERMINAL ROUTES TO</td>
    <td>ATL </td>
    <td>ATN</td>
  </tr>
  <tr>
    <td><b>Terminal Routes</b></td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <td>TERMINAL ROUTES FROM</td>
    <td>LAX </td>
    <td>LAS</td>
  </tr>
  <tr>
    <td>TERMINAL ROUTES TO</td>
    <td>JFK</td>
    <td>LGA </td>
  </tr>
</table>

position()会自动在for-each循环中递增,因此第一个select="//Segment/To[$position]/previous" //Segment/To[1]/previousSegment/From,第二个//Segment/To[2]/previous为{{1}}。<登记/> 供参考:http://msdn.microsoft.com/en-US/en-en/library/ms256233%28v=vs.110%29.aspx