1

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

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

  1. 取两个元素的平均值
  2. 标准化记录间的平均值。

示例:在下面的示例输入文件中为每条记录

  1. 平均值 = (c + d)/2
    • 平均 = (c+d)/2 = (12+12)/2 = 12, (8+12)/2=10 ....
  2. avg_nom = 平均/分钟(平均)
    • avg_nom = avg/min(avg) = 12/min(12,10,15,27)=1.2

输入 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>

代码:此代码是对先前问题的响应,其中示例 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

因此最终输出应如下所示

<?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>
4

1 回答 1

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 处理)转换为单例节点集(它是)。可能在大多数实现中,它是一个很好的空操作。

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

于 2013-10-22T07:12:55.607 回答