XSLT 前同级如何获取前一个非空值

问题描述 投票:0回答:2

我收到一个设计不佳的 CSV 文件,如下所示(此处过于简化):

BizTalk 转换为 XML,但“详细信息”行上缺少“标题”值。我现在需要创建另一个文件,在其中将仪表和状态“下移”到具有卷数据的行。 XML 看起来像这样。

<VendorFile xmlns="http://etc/VendorFile">
    <Row xmlns="">
        <Meter>123</Meter>
        <State>TX</State>
        <StartDate/>
        <Volume/>
    </Row>
    <Row xmlns="">
        <Meter></Meter>
        <State></State>
        <StartDate>1/1/2024</StartDate>
        <Volume>100</Volume>
    </Row>
    <Row xmlns="">
        <Meter></Meter>
        <State></State>
        <StartDate>1/2/2024</StartDate>
        <Volume>110</Volume>
    </Row>
    <Row xmlns="">
        <Meter></Meter>
        <State></State>
        <StartDate>1/3/2024</StartDate>
        <Volume>107</Volume>
    </Row>
    <Row xmlns="">
        <Meter>456</Meter>
        <State>OK</State>
        <StartDate/>
        <Volume/>
    </Row>
    <Row xmlns="">
        <Meter></Meter>
        <State></State>
        <StartDate>1/1/2024</StartDate>
        <Volume>200</Volume>
    </Row>
    <Row xmlns="">
        <Meter></Meter>
        <State></State>
        <StartDate>1/2/2024</StartDate>
        <Volume>205</Volume>
    </Row>
    <Row xmlns="">
        <Meter></Meter>
        <State></State>
        <StartDate>1/3/2024</StartDate>
        <Volume>210</Volume>
    </Row>
</VendorFile> 

所需的输出将如下所示(但字段名称不同,因为我将其映射到另一个内部规范模式)并发送到我们的第三方软件系统之一。

<VendorFile xmlns="http://etc/VendorFile">
    <Row xmlns="">
        <Meter>123</Meter>
        <State>TX</State>
        <StartDate>1/1/2024</StartDate>
        <Volume>100</Volume>
    </Row>
    <Row xmlns="">
        <Meter>123</Meter>
        <State>TX</State>
        <StartDate>1/2/2024</StartDate>
        <Volume>110</Volume>
    </Row>
    <Row xmlns="">
        <Meter>123</Meter>
        <State>TX</State>
        <StartDate>1/3/2024</StartDate>
        <Volume>107</Volume>
    </Row>
    <Row xmlns="">
        <Meter>456</Meter>
        <State>OK</State>
        <StartDate>1/1/2024</StartDate>
        <Volume>200</Volume>
    </Row>
    <Row xmlns="">
        <Meter>456</Meter>
        <State>OK</State>
        <StartDate>1/2/2024</StartDate>
        <Volume>205</Volume>
    </Row>
    <Row xmlns="">
        <Meter>456</Meter>
        <State>OK</State>
        <StartDate>1/3/2024</StartDate>
        <Volume>210</Volume>
    </Row>
</VendorFile> 

到目前为止我的 XSLT 看起来像这样:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:var="http://schemas.microsoft.com/BizTalk/2003/var" exclude-result-prefixes="msxsl var s0" version="1.0" xmlns:ns0="http://etc/GasMeasurementDataCanonical" xmlns:s0="http://etc/VendorFile">
  <xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />
  <xsl:template match="/">
    <xsl:apply-templates select="/s0:VendorFile" />
  </xsl:template>
  <xsl:template match="/s0:VendorFile">
    <ns0:GasMeasurementDataCanonical>
      <xsl:for-each select="Row[StartDate[text()!='']]">
        <Row>
          <Meter_Number>
            <xsl:value-of select="preceding-sibling::Meter[text()!='']" />
          </Meter_Number>
          <On_Date_Time>
            <xsl:value-of select="StartDate/text()" />
          </On_Date_Time>
     ...

对于 Meter_Number - 我想要第一个前面的兄弟(按向后顺序),其中 Meter 不是空字符串。

我从这个开始:

<xsl:for-each select="Row[StartDate[text()!='']]">

这样就可以正确地拉出有卷的行。 现在我需要回头去拿仪表。

这些是我尝试过的一些变化:

<xsl:value-of select="preceding-sibling::Meter[text()!='']" />
<xsl:value-of select="../preceding-sibling::Meter[text()!='']" />
<xsl:value-of select="/*preceding-sibling::Meter[text()!='']" />

是否可以做我想做的事情,以及如何修复 select 语句?

xpath xslt-3.0
2个回答
2
投票

我建议使用

for-each-group group-starting-with
例如

<xsl:for-each-group select="//Row" group-starting-with="Row[normalize-space(Meter) and normalize-space(State)]">
  <xsl:apply-templates select="tail(current-group())"/>
</xsl:for-each-group>

然后与

<xsl:template match="Row">
  <xsl:copy>
    <xsl:apply-templates select="current-group()[1]!(Meter, State), *"/>
  </xsl:copy>
</xsl:template>

您可以转换每行以包含“组标题”中的

Meter
State
信息。我已经使用了
xsl:copy
,但您当然可以使用文字结果元素来创建需要将
Row
转换为的任何元素。


2
投票

失败的主要原因是您的

Row
元素没有名为
Meter
的前同级元素。你想要
preceding-sibling::Row/Meter

谓词

text()!=''
也是错误的。如果一个元素为空,则它没有文本节点;文本节点本身的长度永远不会为零。要测试元素是否为空,请使用谓词
[. != '']
.

© www.soinside.com 2019 - 2024. All rights reserved.