XSLT:for-each-group将一组xml节点转换为并发变量

时间:2017-12-13 15:13:40

标签: xml xslt xslt-grouping

我正在努力应对以下转型。

我的源代码是一个我不了解根节点的XML(它是由ETL动态创建的,我无法输出XML。因此是presumed_root)。

XML来源

<presumed_root>
    <IndexGroup>
        <IndexDate>01/01/2017</IndexDate>
        <IndexRate>US_CPI</IndexRate>
        <IndexValue>190</IndexValue>
    </IndexGroup>
    <IndexGroup>
        <IndexDate>01/04/2017</IndexDate>
        <IndexRate>US_CPI</IndexRate>
        <IndexValue>195</IndexValue>
    </IndexGroup>
    <IndexGroup>
        <IndexDate>01/07/2017</IndexDate>
        <IndexRate>US_CPI</IndexRate>
        <IndexValue>193</IndexValue>
    </IndexGroup>
    [...]
</presumed_root>

所需的XML输出

<root>
<IndexGroup>
    <IndexRate>US_CPI</IndexRate>
    <IndexNumbers>
        <IndexCode>US_CPI@2017</IndexCode>
        <IndexYear>2017</IndexYear>
        <Month01>190</Month01>
        <Month02/>
        <Month03/>
        <Month04>195</Month04>
        <Month05/>
        <Month06/>
        <Month07>193</Month07>
        [...]
    </IndexNumbers>
</IndexGroup>
</root>

所以,我试图通过IndexRate&amp; amp; IndexYear,并将每个月放在一个不同的节点中。

XSL失败

 <xsl:template match="/">

<xsl:for-each-group select="/IndexGroup" group-by="concat(translate(normalize-space(IndexRate),' ','_'),'@',xs:string(year-from-date(xs:date(IndexDate))))"> 
<IndexGroup>

    <xsl:variable name="IndexCode" select="current-group()/translate(normalize-space(IndexRate),' ','_')"/>
    <IndexRate><xsl:value-of select="$IndexCode"/></IndexRate>
    <IndexNumbers>
            <xsl:variable name="IndexCode"><xsl:value-of select="current-grouping-key()"/></xsl:variable><!-- Code = Index @ Year -->
            <xsl:variable name="Month01"><xsl:value-of select="translate(replace(current-group()[month-from-date(xs:date(current-group()/IndexDate))=1]/IndexValue, '\p{Z}+', ''),',','.')"/></xsl:variable>
            <xsl:variable name="Month02"><xsl:value-of select="translate(replace(current-group()[month-from-date(xs:date(current-group()/IndexDate))=2]/IndexValue, '\p{Z}+', ''),',','.')"/></xsl:variable>
        [...]           
    </IndexNumbers>
[...]
</IndexGroup>

使用这种XML结构&amp; XSL,for-each-group根本没有任何组合。 因此,我无法同时填补一年中的所有月份/指数组合。

任何帮助都将不胜感激,请不要犹豫,要求进一步解释/背景/输入/示例。

此致

1 个答案:

答案 0 :(得分:1)

我看到你的XSLT存在一些问题......

  • 您在for-each-group中选择了SELECT TOP 1 value FROM mytable WHERE value IS NOT NULL ORDER BY CASE key WHEN 'B' THEN 0 WHEN 'A' THEN 1 WHEN 'C' THEN 2 ELSE 3 END ASC ,这意味着您的XML的根元素必须是/IndexGroup
  • 您尝试将IndexGroup转换为IndexDate,但格式xs:date不是有效的xs:date。
  • 您正在为DD/MM/YYYY
  • 的孩子创建xsl:variable而不是文字结果元素
  • 由于您按IndexNumbers然后按IndexRate + IndexRate进行分组,我认为您需要为每个组分别进行两次分组。< / LI>

这是我要做的......

XML输入

IndexYear

XSLT 2.0

<presumed_root>
    <IndexGroup>
        <IndexDate>01/01/2017</IndexDate>
        <IndexRate>US_CPI</IndexRate>
        <IndexValue>190</IndexValue>
    </IndexGroup>
    <IndexGroup>
        <IndexDate>01/04/2017</IndexDate>
        <IndexRate>US_CPI</IndexRate>
        <IndexValue>195</IndexValue>
    </IndexGroup>
    <IndexGroup>
        <IndexDate>01/07/2017</IndexDate>
        <IndexRate>US_CPI</IndexRate>
        <IndexValue>193</IndexValue>
    </IndexGroup>
    [...]
</presumed_root>

<强>输出

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="/*">
    <root>
      <xsl:for-each-group select="IndexGroup" group-by="IndexRate">
        <xsl:copy>
          <xsl:copy-of select="IndexRate"/>
          <xsl:for-each-group select="current-group()" 
            group-by="concat(IndexRate,'@',tokenize(IndexDate,'/')[last()])">
            <IndexNumbers>
              <xsl:apply-templates select="@*"/>
              <IndexCode>
                <xsl:value-of select="current-grouping-key()"/>
              </IndexCode>
              <IndexYear>
                <xsl:value-of select="tokenize(IndexDate,'/')[last()]"/>
              </IndexYear>
              <xsl:for-each select="1 to 12">
                <xsl:variable name="month" select="format-number(.,'00')"/>
                <xsl:variable name="pattern" select="concat('\d{2}/',$month,'/\d{2}')"/>
                <xsl:element name="month{$month}">
                  <xsl:value-of 
                    select="current-group()[matches(IndexDate,$pattern)]/IndexValue"/>
                </xsl:element>
              </xsl:for-each>
            </IndexNumbers>
          </xsl:for-each-group>          
        </xsl:copy>
      </xsl:for-each-group>
    </root>
  </xsl:template>

</xsl:stylesheet>