Объединение двух наборов узлов в XSL - PullRequest
2 голосов
/ 21 декабря 2011

У меня есть следующий XML:

<root>
  <row>
    <elem>Timestamp</elem>
    <elem>ERB.CHW.BTU_CV</elem>
    <elem>ERB.CHW.BTU1_CV</elem>
    <elem>ERB.HW.BTU_CV</elem>
    <elem>ERB.HW.BTU1_CV</elem>
    <elem>ERB.KW.DEMAND_CV</elem>
    <elem>ERB.KWH.MT_CV</elem>
    <elem></elem>
  </row>
  <row>
    <elem>2011/09/30 11:21:13.9062</elem>
    <elem>2.307609E+09</elem>
    <elem>1880067</elem>
    <elem>1.068635E+08</elem>
    <elem>1340.386</elem>
    <elem>448.8</elem>
    <elem>1427723</elem>
    <elem></elem>
  </row>
</root>

Я хочу изменить его так, чтобы первый <row> определял новые элементы (через <elem>), а каждый непустой <elem>, который следует, предоставляет значения - например:

<root>
  <row>
    <Timestamp>2011/09/30 11:21:13.9062</Timestamp>
    <ERB.CHW.BTU_CV>2.307609E+09</ERB.CHW.BTU_CV>
    <ERB.CHW.BTU1_CV>1880067</ERB.CHW.BTU1_CV>
    <ERB.HW.BTU_CV>1.068635E+08</ERB.HW.BTU_CV>
    <ERB.HW.BTU1_CV>1340.386</ERB.HW.BTU1_CV>
    <ERB.KW.DEMAND_CV>448.8</ERB.KW.DEMAND_CV>
    <ERB.KWH.MT_CV>1427723</ERB.KWH.MT_CV>
  </row>
</root>

Обратите внимание на две вещи:

  1. Обратите внимание, как пустые <elem> элементы удаляются из исходной структуры.
  2. Это должно работать для любого количества <row> наборов узлов.

Я чувствую, что это должно быть просто, но я изо всех сил пытаюсь даже понять, с чего начать. Помощь

РЕДАКТИРОВАТЬ: RE: # 2 выше, я не собираюсь дублировать исходный <row> набор узлов (который используется для определения новых элементов). Скорее, решение должно работать для любого <row> набора узлов, который содержит точки данных (то есть, если второй <row> набор узлов был продублирован 5 раз подряд).

Ответы [ 2 ]

2 голосов
/ 21 декабря 2011

Это преобразование :

<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="vElems" select=
     "/*/row[1]/elem[normalize-space()]"/>


 <xsl:template match="/*">
  <root>
    <xsl:apply-templates select="row[position() >1]"/>
  </root>
 </xsl:template>

 <xsl:template match="row">
  <row>
   <xsl:apply-templates select="$vElems">
    <xsl:with-param name="pValues"
      select="elem"/>
    </xsl:apply-templates>
  </row>
 </xsl:template>

 <xsl:template match="elem">
  <xsl:param name="pValues"/>
  <xsl:variable name="vPos" select="position()"/>

  <xsl:element name="{.}">
   <xsl:value-of select="$pValues[$vPos]"/>
  </xsl:element>
 </xsl:template>
</xsl:stylesheet>

при применении к следующему документу XML (предоставляется плюс еще одна строка данных) :

<root>
    <row>
        <elem>Timestamp</elem>
        <elem>ERB.CHW.BTU_CV</elem>
        <elem>ERB.CHW.BTU1_CV</elem>
        <elem>ERB.HW.BTU_CV</elem>
        <elem>ERB.HW.BTU1_CV</elem>
        <elem>ERB.KW.DEMAND_CV</elem>
        <elem>ERB.KWH.MT_CV</elem>
        <elem></elem>
    </row>
    <row>
        <elem>2011/09/30 11:21:13.9062</elem>
        <elem>2.307609E+09</elem>
        <elem>1880067</elem>
        <elem>1.068635E+08</elem>
        <elem>1340.386</elem>
        <elem>448.8</elem>
        <elem>1427723</elem>
        <elem></elem>
    </row>
    <row>
        <elem>2011/09/31 11:22:33.9063</elem>
        <elem>3.418609E+10</elem>
        <elem>1991073</elem>
        <elem>1.068635E+08</elem>
        <elem>1340.386</elem>
        <elem>452.5</elem>
        <elem>169578</elem>
        <elem></elem>
    </row>
</root>

дает желаемый, правильный результат :

<root>
   <row>
      <Timestamp>2011/09/30 11:21:13.9062</Timestamp>
      <ERB.CHW.BTU_CV>2.307609E+09</ERB.CHW.BTU_CV>
      <ERB.CHW.BTU1_CV>1880067</ERB.CHW.BTU1_CV>
      <ERB.HW.BTU_CV>1.068635E+08</ERB.HW.BTU_CV>
      <ERB.HW.BTU1_CV>1340.386</ERB.HW.BTU1_CV>
      <ERB.KW.DEMAND_CV>448.8</ERB.KW.DEMAND_CV>
      <ERB.KWH.MT_CV>1427723</ERB.KWH.MT_CV>
   </row>
   <row>
      <Timestamp>2011/09/31 11:22:33.9063</Timestamp>
      <ERB.CHW.BTU_CV>3.418609E+10</ERB.CHW.BTU_CV>
      <ERB.CHW.BTU1_CV>1991073</ERB.CHW.BTU1_CV>
      <ERB.HW.BTU_CV>1.068635E+08</ERB.HW.BTU_CV>
      <ERB.HW.BTU1_CV>1340.386</ERB.HW.BTU1_CV>
      <ERB.KW.DEMAND_CV>452.5</ERB.KW.DEMAND_CV>
      <ERB.KWH.MT_CV>169578</ERB.KWH.MT_CV>
   </row>
</root>
2 голосов
/ 21 декабря 2011

Следующая таблица стилей дает запрошенный результат:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <!-- ignore even-numbered rows -->
    <xsl:template match="row[position() mod 2 = 0]"/>
    <!-- non-empty elem nodes of odd-numbered rows -->
    <xsl:template match="elem[normalize-space()]">
    <xsl:variable name="pos" select="position()"/>
        <xsl:element name="{text()}">
            <xsl:value-of select="../following-sibling::row[1]/elem[$pos]"/>
        </xsl:element>
    </xsl:template>
    <xsl:template match="elem"/>
</xsl:stylesheet>

Объяснение

  • Identity Transform используется для копирования большинства узлов без изменений
  • Все строки с четными номерами изначально пропускаются
  • При обработке (непустых) элементов elem каждой строки с нечетным номером мы берем значение elem в той же позиции в следующем братском элементе строки
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...