合并xslt中列的数字

时间:2012-02-20 14:07:05

标签: templates xslt

我想将.xml文件转换为xslt使用相同模式的另一个.xml文件。原因是将存储在输入文件中的一些基于时间的测量值合并到输出文件的新时基中。 xml文件是来自rrdtool的转储,它无法转换它,因此我尝试使用xslt。 我已经多次使用XSLT了,我得到了它背后的声明性想法,但在这个具体问题中我无法应对它,甚至不知道从哪里开始:

输入xml数据按每个传感器1秒的测量值进行组织。在这个示例中,标题被剥离,有2个传感器有60个时间戳(例如14:09.00 .01 ... .59),但实际上有数千个时间戳:

input.xml:

<timestamp>
  <sensor>1.1</sensor>
  <sensor>2.3</sensor>
</timestamp>
<timestamp>
  <sensor>1.2</sensor>
  <sensor>2.2</sensor>
</timestamp>
...
<timestamp>
  <sensor>1.9</sensor>
  <sensor>NaN</sensor>
</timestamp>

结果输出xml数据应按1分钟的测量值进行组织,因此每60个输入时间戳平均合并为1个新时间戳(例如3600秒到60分钟),仍包括2个传感器:

output.xml:

<timestamp>
  <sensor>1.5</sensor>
  <sensor>2.1</sensor>
</timestamp>

上面的例子非常小,实际上我在一个文件中处理了10.000个时间戳和2个最多24个传感器 - 所以“harcoding”不是一个好的解决方案,它应该是一个基于xslt-1.0模板的解决方案。 我不知道如何绘制几个传感器数据,因为它们被组织在行(“timestamp”标签)中封装的列(“传感器”标签)中。 我不知道如何为每个传感器存储合并的中间值。 有时输入文件中存在无效的测量值“NaN”,只要没有有效值,就会在合并中忽略,输出值也是“NaN”。

所以很多?????

由于    Achim的

2 个答案:

答案 0 :(得分:0)

我假设每个XML文档的每个时间戳的传感器数量相同。在这种情况下,请尝试此XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>

   <xsl:template match="timestamps">
      <timestamp>
         <xsl:apply-templates select="timestamp[1]/sensor"/>
      </timestamp>
   </xsl:template>

   <xsl:template match="sensor">
      <xsl:variable name="position" select="position()"/>
      <xsl:variable name="sensors" select="count(//timestamp/sensor[$position][. != 'NaN'])"/>
      <sensor>
         <xsl:choose>
            <xsl:when test="$sensors &gt; 0">
               <xsl:value-of select="format-number(sum(//timestamp/sensor[$position][. != 'NaN']) div $sensors, '0.00')"/>
            </xsl:when>
            <xsl:otherwise>
               <xsl:text>NaN</xsl:text>
            </xsl:otherwise>
         </xsl:choose>
      </sensor>
   </xsl:template>
</xsl:stylesheet>

当应用于以下XSLT时(仅2个传感器的3个时间戳)

<timestamps>
   <timestamp>
      <sensor>1.1</sensor>
      <sensor>2.3</sensor>
   </timestamp>
   <timestamp>
      <sensor>1.2</sensor>
      <sensor>2.2</sensor>
   </timestamp>
   <timestamp>
      <sensor>1.9</sensor>
      <sensor>NaN</sensor>
   </timestamp>
</timestamps>

生成以下输出:

<timestamp>
   <sensor>1.40</sensor>
   <sensor>2.25</sensor>
</timestamp>

编辑:如果你想将一定数量的时间戳合并在一起,而不是一次性合并,这里是你可以尝试的另一个XSLT样式表(注意,我已经删除了不必要的 xsl:从此版本中选择语句。)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>
   <xsl:param name="group" select="2"/>

   <xsl:template match="timestamps">
      <timestamps>
         <xsl:apply-templates select="timestamp[position() mod $group = 1]"/>
      </timestamps>
   </xsl:template>

   <xsl:template match="timestamp">
      <timestamp>
         <xsl:apply-templates select="sensor" />
      </timestamp>
   </xsl:template>

   <xsl:template match="sensor">
      <xsl:variable name="position" select="position()"/>
      <xsl:variable name="sensors" select="1 + count(../following-sibling::*[not(position() >= $group)]/sensor[$position][. != 'NaN'])"/>
      <sensor>
         <xsl:value-of select="format-number((. + sum(../following-sibling::*[not(position() >= $group)]/sensor[$position][. != 'NaN'])) div $sensors, '0.00')"/>
      </sensor>
   </xsl:template>
</xsl:stylesheet>

在这种情况下,我已经参数化了要合并的时间戳的数量,并为此示例将其设置为2.

当应用于同一XML时,输出以下内容:

<timestamps>
   <timestamp>
     <sensor>1.15</sensor>
     <sensor>2.25</sensor>
   </timestamp>
   <timestamp>
      <sensor>1.90</sensor>
      <sensor>NaN</sensor>
   </timestamp>
</timestamps>

答案 1 :(得分:0)

这个简单的转化(没有xsl:choose,没有xsl:when,没有xsl:otherwize,只有一个模板):

<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="vNumSensors">
      <xsl:for-each select="/*/*">
        <xsl:sort select="count(sensor)"
             data-type="number" order="descending"/>
        <xsl:if test="position() =1">
          <xsl:value-of select="count(sensor)"/>
        </xsl:if>
      </xsl:for-each>
     </xsl:variable>

     <xsl:template match="/">
         <timestamp>
           <xsl:for-each select=
              "(//node())[not(position() > $vNumSensors)]">
            <xsl:variable name="vPos" select="position()"/>

              <sensor>
               <xsl:value-of select=
                "format-number(
                               sum(/*/*/sensor
                                      [position() = $vPos]
                                           [number(.) = number(.)])
                              div
                               count(/*/*/sensor
                                        [position() = $vPos]
                                             [number(.) = number(.)]),
                               '0.00'
                               )
               "/>
              </sensor>
           </xsl:for-each>
         </timestamp>
     </xsl:template>
</xsl:stylesheet>

应用于以下XML文档(从@TimC借用):

<timestamps>
    <timestamp>
        <sensor>1.1</sensor>
        <sensor>2.3</sensor>
    </timestamp>
    <timestamp>
        <sensor>1.2</sensor>
        <sensor>2.2</sensor>
    </timestamp>
    <timestamp>
        <sensor>1.9</sensor>
        <sensor>NaN</sensor>
    </timestamp>
</timestamps>

生成想要的正确结果

<timestamp>
   <sensor>1.40</sensor>
   <sensor>2.25</sensor>
</timestamp>