理解" exsl:node-set"对输入xml的多个操作

时间:2013-10-21 19:01:11

标签: xml xslt

我试图理解“exsl:node-set”的概念及其用法,它可以处理XML中的已处理/生成元素。任何人都可以帮忙

我开始开发一个可以按顺序执行以下活动的XSL代码:

  1. 取两个元素的平均值
  2. 规范化记录的平均值。
  3. 实施例:  在下面的示例输入文件中为每条记录

    1. avg =(c + d)/ 2
      • avg =(c + d)/ 2 =(12 + 12)/ 2 = 12,(8 + 12)/ 2 = 10 ....
    2. avg_nom = avg / min(avg)
      • avg_nom = avg / min(avg)= 12 / min(12,10,15,27)= 1.2
    3. 输入XML

      <?xml version="1.0" encoding="UTF-8"?>
      <top>
          <Level1>
              <Results>
                  <a>no</a>
                  <b>10</b>
                  <b_nom>1.66</b_nom>
                  <c>12</c>
                  <d>9</d>
              </Results>
          </Level1>
          <Level1>
               <Results>
                   <a>no</a>
                   <b>8</b>
                   <b_nom>1.33</b_nom>
                   <c>50</c>
                   <d>12</d>
               </Results>
          <Level1>
          </Level1>
               <Results>
                   <a>no</a>
                   <b>6</b>
                   <b_nom>1</b_nom>
                   <c>55</c>
                   <d>56</d>
               </Results>
          <Level1>
          </Level1>
               <Results>
                   <a>yes</a>
                   <b>23</b>
                   <b_nom>1</b_nom>
                   <c>32</c>
                   <d>34</d>
               </Results>
          </Level1>
      </top>
      

      代码:此代码为provided as a response to earlier question,其中示例XML在树中只有两个级别,即。 <top><Results>

      对于这种方法非常好,但对于上面的XML输入,我丢失了<Level1>的数据。我不理解代码并进行必要的更正。

      <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
       xmlns:exsl="http://exslt.org/common" exclude-result-prefixes="exsl">
      
      <xsl:output indent="yes"/>
      <xsl:strip-space elements="*"/>
      
      <xsl:variable name="step1-result-fragment">
        <xsl:apply-templates select="top" mode="step1"/>
      </xsl:variable>
      
      <xsl:variable name="step1-result" select="exsl:node-set($step1-result-fragment)"/>
      
      <xsl:template match="@* | node()" name="identity">
        <xsl:copy>
          <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
      </xsl:template>
      
      <xsl:template match="@* | node()" mode="step1" name="step1-identity">
        <xsl:copy>
          <xsl:apply-templates select="@* | node()" mode="step1"/>
        </xsl:copy>
      </xsl:template>
      
      <xsl:template match="c" mode="step1">
        <avg><xsl:value-of select="(. + ../d) div 2"/></avg>
        <xsl:call-template name="step1-identity"/>
      </xsl:template>
      
      <xsl:template match="/*">
        <xsl:copy>
          <xsl:variable name="min-avg">
            <xsl:for-each select="$step1-result/top//Results/avg">
              <xsl:sort select="." data-type="number"/>
              <xsl:if test="position() = 1">
                <xsl:value-of select="."/>
              </xsl:if>
            </xsl:for-each>
          </xsl:variable>
          <xsl:apply-templates select="$step1-result/top//Results">
            <xsl:with-param name="min-avg" select="$min-avg"/>
          </xsl:apply-templates>
        </xsl:copy>
      </xsl:template>
      
      <xsl:template match="Results">
        <xsl:param name="min-avg"/>
        <xsl:copy>
          <xsl:apply-templates select="@* | node()">
            <xsl:with-param name="min-avg" select="$min-avg"/>
          </xsl:apply-templates>
        </xsl:copy>
      </xsl:template>
      
      <xsl:template match="avg">
        <xsl:param name="min-avg"/>
        <xsl:call-template name="identity"/>    
        <avg_nom><xsl:value-of select=". div $min-avg"/></avg_nom>
      </xsl:template>
      
      </xsl:stylesheet>
      

      我需要的不仅是对上述代码的修正以获得正确的输出,而且还要进一步理解代码。为此,我想在上面的例子中添加一个额外的步骤

      1. 最后=(b_nom + avg_nom)/ 2
      2. 因此最终输出应如下所示

        <?xml version="1.0"?>
        <top>
            <Level1>
              <Results>
                <a>no</a>
                <b>10</b>
                <b_nom>1.66</b_nom>
                <avg>10.5</avg>
                <avg_nom>1</avg_nom>
                <final>5.5</final>
                <c>12</c>
                <d>9</d>
              </Results>
            </Level1>
            <Level1>
              <Results>
                <a>no</a>
                <b>8</b>
                <b_nom>1.33</b_nom>
                <avg>31</avg>
                <avg_nom>2.95238095238095</avg_nom>
                <final>2.14</final>
                <c>50</c>
                <d>12</d>
              </Results>
            </Level1>
            <Level1>
              <Results>
                <a>no</a>
                <b>6</b>
                <b_nom>1</b_nom>
                <avg>55.5</avg>
                <avg_nom>5.28571428571429</avg_nom>
                <final>3.14</final>
                <c>55</c>
                <d>56</d>
              </Results>
            </Level1>
            <Level1>
              <Results>
                <a>yes</a>
                <b>23</b>
                <b_nom>1</b_nom>
                <avg>33</avg>
                <avg_nom>3.14285714285714</avg_nom>
                <final>2.07</final>
                <c>32</c>
                <d>34</d>
              </Results>
            </Level1>
        </top>
        

1 个答案:

答案 0 :(得分:1)

在XSLT 2.0中,您可以创建一个值为树的变量:

<xsl:variable name="temp">
  <root>
    <xsl:call-template name="do-something"/>
  </root>
</xsl:variable>

然后您可以使用XSLT的全部功能来处理此树

<xsl:apply-templates select="$temp" mode="postprocess"/>

这允许样式表在几个阶段中运行:您可以创建一个中间结果,然后对其进行后处理:您可以根据需要在多个阶段中执行转换。

在XSLT 1.0中,由于在规范开发后期出现了糟糕的设计错误,因此不允许这样做。通过使$temp成为“结果树片段”并禁止对结果树片段执行诸如xsl:apply-templates之类的操作来强制实施限制。

在XSLT 1.0发布后很快就实现了这个错误,并且处理器供应商通过引入扩展函数exslt:node-set()来解决它,而没有引入不符合规范的情况。这允许你写

<xsl:apply-templates select="exslt:node-set($temp)" mode="postprocess"/>

从概念上讲,exslt:node-set()将结果树片段(不允许xsl:apply-templates处理)转换为单例节点集(它是)。可能在大多数实现中,它都是非操作。

我希望这可以帮助您了解样式表正在做什么。