代码之家  ›  专栏  ›  技术社区  ›  NealWalters

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

  •  0
  • NealWalters  · 技术社区  · 2 年前

    我收到一个设计糟糕的CSV文件,看起来像这样(这里过于简化):

    enter image description here

    BizTalk转换为XML,但“详细信息”行中缺少“标头”值。我现在需要创建另一个文件,将Meter和State“向下”到具有卷数据的行。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语句?

    1 回复  |  直到 2 年前
        1
  •  1
  •   Martin Honnen    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
  •  0
  •   Michael Kay    2 年前

    它失败的主要原因是 Row 元素前面没有名为的同级 Meter 。你想要 preceding-sibling::Row/Meter .

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