You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用XSLT的preceding-sibling获取前一个非空Meter值?

解决XSLT中向下填充缺失Meter/State值的问题

针对你遇到的CSV转XML后明细行缺失表头字段、无法通过preceding-sibling获取前序非空值的问题,以下是两种可行的修正方案,适配不同的XML结构场景:


场景假设

先明确典型的XML结构(你可根据实际结构调整):

<Rows>
  <!-- 表头行:含Meter/State,无业务数据 -->
  <Row>
    <Meter>Meter001</Meter>
    <State>CA</State>
    <StartDate></StartDate>
    <Volume></Volume>
  </Row>
  <!-- 明细行:仅含业务数据,缺失Meter/State -->
  <Row>
    <Meter></Meter>
    <State></State>
    <StartDate>2024-01-01</StartDate>
    <Volume>100</Volume>
  </Row>
  <Row>
    <Meter></Meter>
    <State></State>
    <StartDate>2024-01-02</StartDate>
    <Volume>150</Volume>
  </Row>
</Rows>

方案1:使用key分组关联表头与明细行

适合表头行(带Meter/State)与后续明细行连续分组的场景,效率更高:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <!-- 定义key:将明细行关联到最近的前置表头行 -->
  <xsl:key name="detail-group" match="Row[StartDate!='']" use="generate-id(preceding-sibling::Row[Meter[normalize-space()] and State[normalize-space()]][1])"/>

  <xsl:template match="/">
    <Result>
      <!-- 遍历所有表头行,批量处理对应明细 -->
      <xsl:for-each select="Rows/Row[Meter[normalize-space()] and State[normalize-space()]]">
        <xsl:variable name="current-meter" select="Meter"/>
        <xsl:variable name="current-state" select="State"/>
        
        <!-- 输出填充后的明细行 -->
        <xsl:for-each select="key('detail-group', generate-id())">
          <Row>
            <Meter><xsl:value-of select="$current-meter"/></Meter>
            <State><xsl:value-of select="$current-state"/></State>
            <StartDate><xsl:value-of select="StartDate"/></StartDate>
            <Volume><xsl:value-of select="Volume"/></Volume>
          </Row>
        </xsl:for-each>
      </xsl:for-each>
    </Result>
  </xsl:template>
</xsl:stylesheet>

方案2:递归查找最近的非空字段值

适合表头行与明细行无严格连续分组的场景,灵活性更强:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <!-- 主模板:仅处理含StartDate的有效行 -->
  <xsl:template match="/">
    <Result>
      <xsl:apply-templates select="Rows/Row[StartDate!='']"/>
    </Result>
  </xsl:template>

  <!-- 处理明细行,填充缺失字段 -->
  <xsl:template match="Row[StartDate!='']">
    <Row>
      <Meter>
        <xsl:call-template name="find-last-non-empty">
          <xsl:with-param name="node" select="preceding-sibling::Row[1]"/>
          <xsl:with-param name="field" select="'Meter'"/>
        </xsl:call-template>
      </Meter>
      <State>
        <xsl:call-template name="find-last-non-empty">
          <xsl:with-param name="node" select="preceding-sibling::Row[1]"/>
          <xsl:with-param name="field" select="'State'"/>
        </xsl:call-template>
      </State>
      <StartDate><xsl:value-of select="StartDate"/></StartDate>
      <Volume><xsl:value-of select="Volume"/></Volume>
    </Row>
  </xsl:template>

  <!-- 递归模板:向上查找最近的非空字段值 -->
  <xsl:template name="find-last-non-empty">
    <xsl:param name="node"/>
    <xsl:param name="field"/>
    <xsl:choose>
      <!-- 当前节点对应字段非空,返回值 -->
      <xsl:when test="$node and $node/*[local-name()=$field][normalize-space()]">
        <xsl:value-of select="$node/*[local-name()=$field]"/>
      </xsl:when>
      <!-- 当前节点为空,继续向上递归查找 -->
      <xsl:when test="$node">
        <xsl:call-template name="find-last-non-empty">
          <xsl:with-param name="node" select="$node/preceding-sibling::Row[1]"/>
          <xsl:with-param name="field" select="$field"/>
        </xsl:call-template>
      </xsl:when>
      <!-- 无匹配值时返回默认标识 -->
      <xsl:otherwise>
        <xsl-text>N/A</xsl-text>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

常见问题修正

如果你之前用preceding-sibling::Row[Meter!=''][1]无效,大概率是这两个原因:

  1. 空值判断不准确:原XML中的空值可能是空白字符而非空字符串,需用Meter[normalize-space()]代替Meter!='',normalize-space()会自动过滤空白。
  2. 上下文节点错误:如果先筛选了有效行,preceding-sibling是基于原XML节点位置而非筛选后的结果集,此时需将筛选后的行存入变量,再通过位置索引查找前序节点。

内容的提问来源于stack exchange,提问作者NealWalters

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 12:22:30