объединение чисел по столбцам в xslt - PullRequest
0 голосов
/ 20 февраля 2012

Я хочу преобразовать файл .xml в другой файл .xml той же схемы с помощью xslt. Причина состоит в том, чтобы объединить некоторые основанные на времени измерения, хранящиеся во входном файле, в новую временную базу в выходной файл. XML-файл является дампом из rrdtool, который не может конвертировать его, поэтому я пробую его с помощью xslt. Я использовал XSLT несколько раз, и у меня есть декларативные идеи, но в этой конкретной проблеме я не могу справиться, даже не знаю, с чего начать:

Входные данные XML организованы по измерениям по 1 секунде для каждого датчика. В этом примере заголовок удален, для двух датчиков есть 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 датчиков - так что «хардкодирование» не является хорошим решением, оно должно быть решением на основе шаблона xslt-1.0. Я не знаю, как получить несколько данных датчиков, потому что они организованы в столбцы (тег «датчик»), инкапсулированные в строки (тег «метка времени»). Я не знаю, как хранить промежуточные значения для консолидации для каждого датчика. Иногда во входном файле есть недопустимые значения измерения «NaN», которые должны игнорироваться при консолидации, если ни одно из них не является действительным, тогда выходное значение также равно «NaN».

Так много ?????

Спасибо Ахим

Ответы [ 2 ]

0 голосов
/ 20 февраля 2012

Это простое преобразование (нет 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>
0 голосов
/ 20 февраля 2012

Я предполагаю, что количество датчиков для каждой временной метки одинаково для каждого 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 (только для 3 временных меток для 2 датчиков)

<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, которую вы можете попробовать (Примечание: я удалил ненужные 1012 * 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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...