xpath1.0和2.0_使用XPath 2.0和XSLT 2.0节省时间和代码

xpath1.0和2.0

XPath 2.0和XSLT 2.0中的主要新概念之一是,一切都是序列。 在XPath 1.0和XSLT 1.0中,通常使用节点树。 解析的XML文档是一棵包含文档节点及其后代的树。 使用该节点树,您可以找到根元素的节点,以及所有根元素的后代,属性和同级。 (XML文件的根元素之外的任何注释或处理指令都被视为根元素的同级。)

在XPath 2.0和XSLT 2.0中使用XML文档时,使用序列的方式与XPath 1.0和XSLT 1.0中的树结构相同。 该序列包含一个项目(文档节点),并且您将始终以相同的方式使用它。 但是,您可以创建原子值序列。 清单1摘自即将到来的示例应用程序,您将在其中管理16队单淘汰赛的数据,该示例显示了一系列原子值的示例。

清单1.原子值序列
<xsl:variable name="seeds" as="xs:integer*">
  <xsl:sequence 
    select="(1, 16, 8, 9, 5, 12, 4, 13, 6, 11, 3, 14, 7, 10, 2, 15)"/>
</xsl:variable>

这段代码定义了变量$seeds 。 如您所料,新的<xsl:sequence>元素定义了一系列项目。 在这种情况下,这些项目是XML Schema xs:integer 。 新的as属性定义变量的数据类型,星号( xs:integer* )表示该序列包含零个或多个整数。 在XPath 1.0和XSLT 1.0中,您将创建16个不同的文本节点,然后将这些节点分组为一个变量。 在XPath 2.0和XSLT 2.0中,该序列充当一维数字数组,这正是示例应用程序所需要的。

序列遵循两个规则。 首先,它们不能包含其他序列。 如果从三个项目的序列中创建一个新序列,然后再从三个项目的序列中创建一个新序列,则结果将是六个项目的新序列。 其次,序列允许您混合节点和项目。 您可以创建一个包含清单1中所示的原子值以及所有<contestant>元素的序列,如清单2所示

清单2.一系列节点和原子值
<xsl:variable name="seeds" as="item()*">
  <xsl:for-each select="/bracket/contestants/contestant">
    <xsl:copy-of select="."/>
  </xsl:for-each>
  <xsl:sequence 
    select="(1, 16, 8, 9, 5, 12, 4, 13, 6, 11, 3, 14, 7, 10, 2, 15)"/>
</xsl:variable>

变量$seeds包含所有竞争者节点和您先前使用的16个原子值。 请注意,变量的数据类型为item()* 。 项目是节点或原子值,因此此变量可以包含任何内容。

现在您已经了解了序列和项目的基础,让我们看一下to运算符,它是XPath 2.0和XSLT 2.0中的新增功能。 它允许您选择整数范围。 例如,您可以创建一个清单3所示的序列。

清单3.使用to运算符创建的整数序列
<xsl:variable name="range" as="item()*">
  <xsl:sequence select="1 to 16"/>
</xsl:variable>

这段代码创建了一个名为$range的变量,该变量包含从1到16的整数。在示例应用程序中,可以将to运算符用作循环机制,如清单4所示。

清单4.使用to运算符进行循环
<xsl:for-each select="1 to 32">
  <!-- Do something useful here -->
</xsl:for-each>

在构建样式表之前,请更详细地查看示例应用程序。

了解示例应用程序

在本文的示例应用程序中,您将管理16队单淘汰赛的数据。 如您所料,锦标赛数据以XML表示。 您将创建一个XSLT 2.0样式表,该样式表将XML数据转换为演示锦标赛结果HTML表。 清单5显示了XML文档格式。

清单5.带有锦标赛数据的XML文档
<?xml version="1.0" encoding="UTF-8"?>
<!-- tourney.xml -->
<bracket>
   <title>RSDC Smackdown</title>
   <contestants>
      <contestant seed="1" image="images/homerSimpson.png">Donuts</contestant>
      <contestant seed="2" image="images/caffeine.png">Caffeine</contestant>
      <contestant seed="3" image="images/fearlessFreep.png">Fearless Freep</contestant>
      <contestant seed="4" image="images/wmd.jpg">Weapons of Mass Destruction</contestant>
      <contestant seed="5" image="images/haroldPie.jpg">Pie</contestant>
      <contestant seed="6" image="images/adamAnt.png">Adam Ant</contestant>
      <contestant seed="7" image="images/georgeWBush.jpg">Misunderestimated</contestant>
      <contestant seed="8" image="images/sillyPutty.jpg">Silly Putty</contestant>
      <contestant seed="9" image="images/krazyGlue.jpg">Krazy Glue</contestant>
      <contestant seed="10" image="images/snoopDogg.png">Biz-Implification</contestant>
      <contestant seed="11" image="images/atomAnt.png">Atom Ant</contestant>
      <contestant seed="12" image="images/ajaxcan.png">AJAX</contestant>
      <contestant seed="13" image="images/darthVader.jpg">Darth Vader</contestant>
      <contestant seed="14" image="images/nastyCanasta.png">Nasty Canasta</contestant>
      <contestant seed="15" image="images/jcp.png">Java Community Process</contestant>
      <contestant seed="16" image="images/andre.png">Andre the Giant</contestant>
   </contestants>
   <results>
      <result round="1" firstSeed="1" secondSeed="16" winnerSeed="1"/>
      <result round="1" firstSeed="8" secondSeed="9" winnerSeed="9"/>
      <result round="1" firstSeed="5" secondSeed="12" winnerSeed="5"/>
      <result round="1" firstSeed="4" secondSeed="13" winnerSeed="4"/>
      <result round="1" firstSeed="6" secondSeed="11" winnerSeed="11"/>
      <result round="1" firstSeed="3" secondSeed="14" winnerSeed="3"/>
      <result round="1" firstSeed="7" secondSeed="10" winnerSeed="10"/>
      <result round="1" firstSeed="2" secondSeed="15" winnerSeed="2"/>
      <result round="2" firstSeed="1" secondSeed="9" winnerSeed="1"/>
      <result round="2" firstSeed="5" secondSeed="4" winnerSeed="5"/>
      <result round="2" firstSeed="11" secondSeed="3" winnerSeed="3"/>
      <result round="2" firstSeed="10" secondSeed="2" winnerSeed="2"/>
      <result round="3" firstSeed="1" secondSeed="5" winnerSeed="1"/>
      <result round="3" firstSeed="3" secondSeed="2" winnerSeed="2"/>
      <result round="4" firstSeed="1" secondSeed="2" winnerSeed="2"/>
   </results>
</bracket>

<title>元素中,您可以看到锦标赛的名称RSDC Smackdown。 本文档代表了今年IBM Rational Software Developer Conference上的一次会议的实际结果。

方括号包含16个<contestant>元素,每个元素都有一个名称(其文本),一个种子和一个图像。 一个由16支球队组成的锦标赛包括15场比赛。 每个比赛由一个<result>元素表示。 每个比赛都有四段数据:比赛发生的那round比赛的roundround属性),两个参赛者的种子(存储在firstSeedsecondSeed属性中)以及获胜者的种子(the winnerSeed属性)。 您的任务是获取这个XML文档,并将其转换为显示结果HTML表, 如图1所示。

图1.比赛结果显示在HTML表中
比赛结果在HTML表格中

该表有32行和5列。 使用XSLT 1.0方法,您可以一次构建一行HTML表,如清单6所示。

清单6.一次一行地构建HTML表
<!-- Row 1 -->
<tr>
  <td style="border: none; border-top: solid; border-right: solid;">
    <xsl:text>[1] </xsl:text>
    <xsl:value-of select="$contestants[@seed='1']/>
  </td>
  <td style="border: none;>
    &nbsp;
  </td>
  <td style="border: none;>
    &nbsp;
  </td>
  <td style="border: none;>
    &nbsp;
  </td>
  <td style="border: none;>
    &nbsp;
  </td>
</tr>
<!-- Row 2 -->
. . .

那会起作用,但是样式表将很难维护。 在整个样式表中,重复每一行和每一列的代码。 这里的主要问题是输出表中需要32行。 32行中的每一行都包含来自XML文档中的元素( <contestant><result> )的数据。 不幸的是,您没有可以迭代的32个元素。 您可以使用<xsl:for-each select="contestants/contestant|results/result"> ,但是这些元素不会按照您在表中需要的顺序显示。 XSLT 1.0没有很多工具可以帮助您。

您可以重构代码以使样式表更加简单。 单元格的样式和内容中包含一些模式,您可以使用XPath 2.0和XSLT 2.0的新功能来遍历这些模式。 最终的样式表比(公认的笨拙的)原始版本小大约70%。 在构建样式表之前,让我们看一下如何重构代码。

重构代码-计算表格单元格样式

要重构代码,请开始将样式信息移至CSS样式表。 如图2所示 ,HTML括号表具有五种不同的单元格样式: NoneMatchupStartMatchupMiddleMatchupEndSolid

图2. HTML表中的单元格边框样式
HTML表格中的单元格边框样式

清单7显示了CSS代码的样子。

清单7. CSS样式表
.None          { width: 20%; }
.MatchupStart  { width: 20%; 
                 border: none; border-top: solid; 
                 border-right: solid; }
.MatchupMiddle { width: 20%; 
                 border: none; border-right: solid; }
.MatchupEnd    { width: 20%; 
                 border: none; border-bottom: solid; 
                 border-right: solid; }
.Solid         { width: 20%; 
                 border: solid; }

边框样式易于查看比赛的结果。 连接两个单元的水平线表示这两个竞争者彼此面对。 在下栏中带有实线边框的单元格表示比赛的获胜者。 查看边框样式,您可以看到一个确定的模式:对于每对竞争对手,第一个竞争对手之前的单元格都没有边界(样式None ),两个竞争对手的单元格都有实线边界( Solid样式),这些单元格两个竞争对手之间的边框在右边有一个边框(样式MatchupMiddle ),最后一个竞争对手之后的单元格没有边框(样式None )。 这与第一列略有不同。 因为第一列中的一对竞争者是如此接近,所以第一个竞争对手的单元格在顶部和右侧都有边框(样式MatchupStart ),而第二个竞争对手的单元格在底部和右侧则带有边框(样式) MatchupEnd )。

请注意,成对的竞争者在每一列中相距较远。 第1列的竞争者之间有一个单元格的间隙,第2列的竞争者之间有一个三单元格的间隙,第3列的竞争者之间有一个7单元格的间隙,第4列中的每个单元格的大小小于1。 2的幂,所以这里有一个确定的模式。

表格中的通用模式是每列包含重复的单元格组。 五个重复列的重复组的大小(为更好的术语,我将其称为列的周期 )分别为4、8、16、32和64。 每个重复组包含两个竞争者,两个竞争者之间的单元以及两个竞争者之前和之后的单元。

在每一列中,在计算中使用两个值: $period ,它代表重复组的大小; $oneQuarter ,它是周期大小的四分之一。 (将$period div 4存储在变量中可使代码更简洁。) 表1显示了单元格边框样式的通用规则。

表1. HTML表中的单元格边框样式
第1栏(期间4) 第2栏(期间8) 第3栏(期间16) 第4栏(期间32) 第5栏(期间64)
$row < $oneQuarter or $row > $period - $oneQuarter 不适用 第1行 ,样式None 第1-3行 ,样式None 第1至7行 ,样式None 第1-15行 ,样式为None
$row = $oneQuarter 第1行 ,样式为MatchupStart 第2行Solid样式 第4行Solid样式 第8行Solid样式 第16行Solid样式
$row > $oneQuarter and $row < $period - $oneQuarter 第2行 ,样式MatchupMiddle 第3-5行 ,样式为MatchupMiddle 第5-11行 ,样式为MatchupMiddle 第9-23行 ,样式为MatchupMiddle 第17-32行 ,样式: None
$row = $period - $oneQuarter 第3行 ,样式MatchupEnd 第6行Solid样式 第12行Solid样式 第24行Solid样式 不适用
$row < $oneQuarter or $row > $period - $oneQuarter 第4行 ,样式None 第7-8行 ,样式为None 第13-16行 ,样式为None 第25-32行 ,样式为None 不适用

现在,您已经创建了一种优雅的方法来找出表中任何给定单元格的样式。 给定列号和行号,该公式的作用就像一个超级按钮。

重构代码-计算表格单元格的内容

当然,在表中创建单元格时,还需要在该单元格中放入适当的内容。 那也有一个不错的模式。 样式为NoneMatchupMiddle任何内容都根本没有任何内容。 这意味着您只需要担心使用其他三种样式为单元格找到正确的内容。

表1中 ,您可以看到具有内容的单元格具有属性$row = $oneQuarter or $row = $period - $oneQuarter 。 对于第一列,您只需编写种子和相应参赛者的姓名。 配对基于种子,并具有表2中所示的配对。

表2.基于种子的匹配
根据种子配对
[1]与[16]
[8]与[9]
[5]与[12]
[4]与[13]
[6]与[11]
[3]与[14]
[7]与[10]
[2]与[15]

安排比赛,以便如果总是获得较高的种子,则种子排名最高的球队将始终扮演剩下的种子人数最少的球队,种子排名第二的球队将始终扮演剩下的种子人数第二低的球队,依此类推。 以这种顺序查看种子(1、16、8、9、5、12、4、13、6、11、3、14、7、10、2、15),可以看到它们与序列$seeds 。 竞争对手按此顺序显示在第1列中。

竞争对手每隔一行出现一次,这意味着第1行具有序列中的第一个种子,第3行具有序列中的第二个种子,第5行具有序列中的第三个种子,依此类推。 这里的模式是$row + 1 div 2 = $index 。 换句话说,取行号,加1,然后除以2,得到$seeds序列中种子的索引。 表格单元格的内容是种子编号,后跟带有该种子的参赛者的姓名。

这样就可以处理第1列的内容了。如您所料,第2列到第5列更加复杂。 您无需查看<contestant>元素,而需要查看显示在15个<result>元素中的<result>

第2列包含第一轮的获胜者。这意味着您需要查看具有属性round="1"<result>元素。 为了简化起见,第一个比赛的获胜者(1到16种子)存储在第一个<result>元素中,第二个比赛的获胜者(8到9种子)存储在第二个<result>元素中, 等等。 第2列中的获胜者显示在第2、6、10、14、18、22、26和30行中。为寻找模式,第2行使用第一个<result>元素,第6行使用第二个,而第10行使用第三个。 对于此列,如果采用行号,将其加2,然后除以4,就可以得到适当的<result round="1">元素的位置。

第3列和第4列的处理方式类似。 第3列的获胜者显示在第4、12、20和28行中(此处的模式是将4加除以8)。 第4列的获胜者显示在第8行和第24行(加8并除以16)。 第5栏仅显示一名参赛者,即整个比赛的获胜者。 如果您位于第16行,则显示单个<result round="4">元素中的获胜者。

查找所寻找值位置的重构方法是($row + $oneQuarter) div ($oneQuarter * 2) 。 使用不断增加的重复模式大小可以简化代码。 对于第1列,计算出的位置是种子序列的索引; 对于其他列,计算出的位置是适当的<result>元素的位置。

现在,您可以用一种优雅的方式来确定表中每个单元格的内容和样式。 给定行号和列号,您可以找出所有需要了解的内容。

利用XPath 2.0和XSLT 2.0的强大功能

现在,您可以使用XPath 2.0和XSLT 2.0中可用的新技术来简化样式表。 首先,使用to运算符。 如果使用过程编程语言构建表,则可能会执行类似于清单8的操作

清单8.样式表的过程方法
for (int row=1; row<=32; row++)
        for (int column=1; column<=5; column++)
          // Build each cell in the table here

在XPath 2.0和XSLT 2.0中,您可以使用<xsl:for-each>替换您在过程语言中使用的for循环。 清单9显示了如何。

清单9.使用to运算符for循环
<xsl:for-each select="1 to 32">
  <xsl:variable name="outerIndex" select="."/>
    <tr>
      <xsl:for-each select="1 to 5">

您需要在此处解决一些复杂问题。 首先,在XPath 1.0和XSLT 1.0中,使用<xsl:for-each>更改每次迭代的上下文。 例如,如果您使用<xsl:for-each select="contestants/contestant> ,则上下文节点是每次迭代中最新的<contestant> 。当您使用to运算符迭代各个整数时,上下文项(即。在2.0上下文项 ) 未定义正如你可以看到清单9 ,需要保存外的当前值<xsl:for-each> ,因为它不是提供给在所述内<xsl:for-each>

但情况变得更糟。 如果上下文项未定义, 则无法从文档中选择节点 。 如果您知道自己位于第1行第1列,则可以从$seeds序列中获取第一项,因为$seeds是全局变量。 这表明您需要找到<contestant seed="1">元素。 不幸的是,您无法找到文档中的任何内容。 即使使用绝对的XPath表达式,例如/bracket/contestants/contestant[@seed='1']也不起作用。 因此,您需要将您关心的节点存储为全局变量。 清单10显示了如何随时随地访问全局变量。

清单10.存储所需节点的全局变量
<xsl:variable name="results" select="/bracket/results"/>

<xsl:variable name="contestants" select="/bracket/contestants"/>

如果需要获取第16个种子竞赛者的名称,则XPath表达式为$contestants/contestant[@seed="16"] 。 您可以类似地访问<result>元素。 如果您需要在第2轮中获得第二场比赛的获胜者,则表达式为$results/result[@round="2"][2]/@winnerSeed清单11显示了两个可用于生成HTML表的全局变量。

清单11.其他有用的全局变量
<xsl:variable name="periods" as="xs:integer*">
  <xsl:sequence select="(4, 8, 16, 32, 64)"/>
</xsl:variable>

<xsl:variable name="backgroundColors" as="xs:string*">
  <xsl:sequence 
    select="('background: #CCCCCC;', 'background: #9999CC;',
             'background: #99CCCC;', 'background: #CC99CC;',
             'background: #CCCC99;')"/>
</xsl:variable>

这些变量存储每列的期间值和每列的背景色。 要使用每个变量,只需将列号用作所需的单个值的索引。

XPath 2.0和XSLT 2.0中的另一个不错的增强是<xsl:function>元素。 让我们在样式表中创建两个函数: cellStylegetResults 。 第一个函数返回每个单元格的边框样式,第二个函数返回给定匹配的结果(如果有)。 这两个函数的参数都是单元格的行号和列号。 清单12演示了cellStyle函数的代码。

清单12. cellStyle函数
<xsl:function name="bracket:cellStyle" as="xs:string">
  <xsl:param name="row" as="xs:integer"/>
  <xsl:param name="column" as="xs:integer"/>
  
  <xsl:variable name="period" as="xs:integer"
    select="subsequence($periods, $column, 1)"/>
  <xsl:variable name="oneQuarter" as="xs:integer"
    select="$period div 4"/>
  <xsl:variable name="lastColumn" as="xs:boolean"
    select="$oneQuarter = count($contestants/contestant)"/>
  <xsl:variable name="position" select="$row mod $period"/>
  
  <xsl:value-of 
    select="if ($position = $oneQuarter) then
                (if ($column = 1) then 'MatchupStart'
                    else 'Solid')
            else if ($position = $period - $oneQuarter) then
                     (if ($column = 1) then 'MatchupEnd'
                         else 'Solid')
            else if ($lastColumn) then 'None'
            else if ($position &lt; $oneQuarter or 
                     $position &gt; $period - $oneQuarter) then 'None'
            else 'MatchupMiddle'"/>
</xsl:function>

在确定单元格样式之前,请使用四个变量。 您从全局变量$periods检索$period的值。 如前所述, $oneQuarter只是$period div 4 。 布尔值$lastColumn只是将$oneQuarter与锦标赛中参赛者的数量进行比较。 如果这些值相等,则您正在处理最后一列。 最后,变量$position表示模式中当前行的位置。 换句话说,表中的第9行是第1列和第2列的重复组的第一行。使用该行在模式中的位置以找出单元格样式。

XPath 2.0和XSLT 2.0具有if运算符,该运算符具有一个表达式(用括号括起来),后跟一个then和一个else 。 所有这些都进入<xsl:value-of>select属性。 在此示例中,用单个表达式替换了更为冗长的<xsl:choose>元素。 考虑到表公式的讨论,此处的代码非常简单。 如果逻辑更复杂,则使用<xsl:choose>可能更易于维护,即使它需要更多类型输入。

<xsl:function>一些语法说明:首先,您需要为函数声明一个新的名称空间。 如果在XPath表达式中调用方bracket:cellStyle() ,则名称空间将告诉XSLT 2.0处理器如何查找该函数。 其次,请注意,您使用了as="xs:string"属性来指示此函数返回一个字符串。 <xsl:value-of>元素返回五个样式名称之一; 那是函数的输出。

清单13所示getResults函数稍微复杂一点,但并不复杂。

清单13. getResults函数
<xsl:function name="bracket:getResults" as="xs:string">
  <xsl:param name="row" as="xs:integer"/>
  <xsl:param name="column" as="xs:integer"/>
  
  <xsl:variable name="period" as="xs:integer"
    select="subsequence($periods, $column, 1)"/>
  <xsl:variable name="oneQuarter" as="xs:integer"
    select="$period div 4"/>
  <xsl:variable name="position" select="$row mod $period"/>
  
  <xsl:choose>
    <xsl:when test="$position = $oneQuarter
                    or
                    $position = $period - $oneQuarter">
      <xsl:variable name="round" select="$column - 1"/>
      <xsl:variable name="index" 
        select="($row + $oneQuarter) div ($oneQuarter * 2)"/>
      <xsl:variable name="currentSeed"
        select="if ($column = 1) then 
                  subsequence($seeds, $index, 1)
                else
                  $results/result[@round=$round][$index]/@winnerSeed"/>
      <xsl:choose>
        <xsl:when test="string-length(string($currentSeed))">
          <xsl:value-of 
            select="concat('[', $currentSeed, '] ', 
                    $contestants/contestant[@seed=$currentSeed])"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:text>&#160;</xsl:text>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:when>
    <xsl:otherwise>
      <xsl:text>&#160;</xsl:text>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

您具有与以前相同的参数。 您必须在此处对第1列进行一些特殊处理,该列包含<contestant>元素的数据,而其他列则包含<result>元素的数据。 与cellStyle函数一样,您可以计算$period$position ,并使用$oneQuarter变量简化公式。

如果单元格中包含竞赛者,则需要再计算三个变量。 $round变量比列小1(第2列包含来自第1轮的结果),然后根据前面讨论的公式计算$index变量。

您需要遵循两个步骤来找到适当的数据。 首先,设置$currentSeed变量的值。 如果是第1轮,则可以使用新的子subsequence函数从$seeds变量中选择一个值。 在其他回合中,您将从相应的<result>元素中获得winnerSeed属性。

其次,除了以不同方式处理第1列之外,您还需要考虑<result>元素没有获胜者的可能性( winnerSeed="" )。 如果发生这种情况,请返回一个不间断的空格( &#160; )。 由于XSLT 2.0处理数据类型的方式(这是以后的文章的主题),因此需要将$currentSeed转换$currentSeed字符串,然后测试字符串的长度。 如果字符串的长度为零,则返回一个不间断的空格;否则,返回0。 否则,返回种子和参赛者的姓名。

最后,请注意您在此处使用<xsl:choose> 。 尽管您可以使用单个XPath if语句完成所有操作,但是代码将很笨拙。 即使<xsl:choose>更加冗长,代码也更加简洁易懂。

现在,您已经设置了所需的全局变量和函数,样式表的核心变得简单而优雅,如清单14所示

清单14.样式表的核心
<xsl:for-each select="1 to 32">
  <xsl:variable name="outerIndex" select="."/>
  <tr>
    <xsl:for-each select="1 to 5">
      <td style="{subsequence($backgroundColors, ., 1)}"
          class="{bracket:cellStyle($outerIndex, .)}">
        <xsl:value-of 
          select="bracket:getResults($outerIndex, .)"/>
      </td>
    </xsl:for-each>
  </tr>
</xsl:for-each>

您有两个循环为表的32行创建五列。 对于每个单元格,背景色基于当前列号。 cellStyle函数确定边框样式( class="x" ),而getResults函数确定单元格的值。

使用样式表

如您所料,需要使用XSLT 2.0处理器才能使用此样式表。 我不会在此处重新打印整个样式表,但是您必须使用<xsl:stylesheet version="2.0">这样处理器才能在XSLT 2.0模式下运行。 我强烈推荐Michael Kay的Saxon处理器( 有关更多详细信息,请参阅参考资料 )。 Kay博士是XSLT 2.0规范的编辑,而Saxon在某种程度上是开发规范时的测试用例。 如果您使用Saxon,请使用以下命令使用样式表results-html.xsl转换XML文件tourney.xml并将输出写入results.html文件:

java net.sf.saxon.Transform -o results.html tourney.xml results-html.xsl

为了说明样式表的灵活性,请取出XML文件中的一些结果并运行转换。 清单15显示了<result>元素的外观。

清单15.具有不完整锦标赛数据的XML文档
<?xml version="1.0" encoding="UTF-8"?>
<!-- incomplete-tourney.xml -->
<bracket>
. . .
   <results>
      <result round="1" firstSeed="1" secondSeed="16" winnerSeed="1"/>
      <result round="1" firstSeed="8" secondSeed="9" winnerSeed="9"/>
      <result round="1" firstSeed="5" secondSeed="12" winnerSeed="5"/>
      <result round="1" firstSeed="4" secondSeed="13" winnerSeed="4"/>
      <result round="1" firstSeed="6" secondSeed="11" winnerSeed="11"/>
      <result round="1" firstSeed="3" secondSeed="14" winnerSeed="3"/>
      <result round="1" firstSeed="7" secondSeed="10" winnerSeed="10"/>
      <result round="1" firstSeed="2" secondSeed="15" winnerSeed="2"/>
      <result round="2" firstSeed="" secondSeed="" winnerSeed=""/>
      <result round="2" firstSeed="" secondSeed="" winnerSeed=""/>
      <result round="2" firstSeed="" secondSeed="" winnerSeed=""/>
      <result round="2" firstSeed="" secondSeed="" winnerSeed=""/>
      <result round="3" firstSeed="" secondSeed="" winnerSeed=""/>
      <result round="3" firstSeed="" secondSeed="" winnerSeed=""/>
      <result round="4" firstSeed="" secondSeed="" winnerSeed=""/>
   </results>
</bracket>

清单15表示第一轮比赛后的比赛状态。 第2、3和4回合的所有<result>元素都有一个空的winnerSeed属性。 尽管如此,样式表仍会生成正确的括号, 如图3所示

图3.不完整锦标赛的括号
括号不完整

摘要

本文演示了XPath 2.0和XSLT 2.0的许多新功能。 在示例应用程序中,您获取了一个笨拙的样式表,并将其重构为更小,更易维护的代码段。 您的一部分工作是分析代码以查找模式,但是如果没有to运算符<xsl:function>和项目序列,那么就很难像您那样精简样式表。

最重要的是,您创建了可以处理任意数量参与者的通用函数。 例如,要更改样式表以处理32队比赛,您需要更改序列$seeds$periods 。 您还需要将select="1 to 5"替换为select="1 to $rounds" ,其中$rounds代表锦标赛中的回合数。 当然,最优雅的解决方案是创建XSLT 2.0函数,该函数计算任何通用括号的值,包括回合数,种子序列(32队括号中的1和32、2和31之间的对位,等等),以及各个列的时间段。 这项挑战留给读者练习。

问题的核心是您需要遍历表的32行,但是XSLT 1.0没有提供执行此操作的实用方法。 XPath 2.0和XSLT 2.0的新功能可以帮助您解决此问题。


翻译自: https://www.ibm.com/developerworks/xml/library/x-xslt20xpath20/index.html

xpath1.0和2.0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值