【问题标题】:I want to better understand XSLT 1.0 nested grouping using Muenchian grouping我想更好地理解使用 Muenchian 分组的 XSLT 1.0 嵌套分组
【发布时间】:2014-09-18 15:15:12
【问题描述】:

我有 XML 数据,想按 INSPTR 和 ELVINSP_DT 对其进行分组。文章末尾的问题。

这是我的 XML:

<AS400_ELVPINS00Collection>
  <ObjList>
    <AS400_ELVPINS00>
      <ID>123456</ID>
      <ELVINSP_DT>2014-05-01</ELVINSP_DT>
      <DetailData>Out Sick</DetailData>
      <INSPTR>
        <ID>555123</ID>
        <INSPTR_NAME>Doe, John P</INSPTR_NAME>
        <MoreDetailData>Northeast Region</MoreDetailData>
      </INSPTR>
    </AS400_ELVPINS00>
    <AS400_ELVPINS00>
      <ID>123459</ID>
      <ELVINSP_DT>2014-05-02</ELVINSP_DT>
      <DetailData>Nobody showed up</DetailData>
      <INSPTR>
        <ID>555123</ID>
        <INSPTR_NAME>Doe, John P</INSPTR_NAME>
        <MoreDetailData>Northeast Region</MoreDetailData>
      </INSPTR>
    </AS400_ELVPINS00>
    <AS400_ELVPINS00>
      <ID>123463</ID>
      <ELVINSP_DT>2014-05-01</ELVINSP_DT>
      <DetailData>Job Location was clear</DetailData>
      <INSPTR>
        <ID>555124</ID>
        <INSPTR_NAME>Smith, John T</INSPTR_NAME>
        <MoreDetailData>South Central Region</MoreDetailData>
      </INSPTR>
    </AS400_ELVPINS00>
  </ObjList>
</AS400_ELVPINS00Collection>

我想要这样列出的数据:

Doe, John P  
 2014-05-01 - Out Sick  
 2014-05-02 - Nobody showed up  
Smith, John T  
 2014-05-01 - Job Location was clear  

这是我正在为 XSLT 尝试的内容:

  <xsl:key name="keyInsptr" match="ObjList/AS400_ELVPINS00" use="INSPTR" />
  <xsl:key name="keyDate" match="ObjList/AS400_ELVPINS00" use="ELVINSP_DT" />

    <fo:flow flow-name="xsl-region-body">
      <xsl:for-each select="ObjList/AS400_ELVPINS00[generate-id(.)=generate-id(key('keyInsptr',INSPTR)[1])]">
        <xsl:sort select="INSPTR/INSPTR_NAME"/>

        <!-- This part works --> 
        <fo:block>
          <xsl:value-of select="INSPTR/INSPTR_NAME" />
        </fo:block>

        <!-- This part DOES NOT work -->
        <xsl:variable name="vrInsptID">
          <xsl:value-of select="INSPTR/INSPTR_NAME"/>
        </xsl:variable>
        <xsl:variable name="lstInsp" select="ObjList/AS400_ELVPINS00[INSPTR/INSPTR_NAME=vrInsptrID]" />
        <xsl:for-each select="lstInsp[generate-id(.)=generate-id(key('keyDate',ELVINSP_DT)[1])]">
          <fo:block>
            <xsl:text> - </xsl:text>
            <xsl:call-template name="dateFormat">
              <xsl:with-param name="value" select="lstInsp/ELVINSP_DT" />
            </xsl:call-template>
          </fo:block>
        </xsl:for-each>


      </xsl:for-each>
    </fo:flow>

我知道 generate-id 会在运行时为元素创建一个唯一的“id”,所以我假设 generate-id(.) 将为每个 ObjList/AS400_ELVPINS00 元素生成一个 id 以在匹配中使用,对吗?

generate-id(key('keyInsptr',INSPTR)[1]) 是做什么的?这会产生什么样的结果?我试图形象化这一点。

当我在 keyInsptr 上执行“for-each”时,我在该 for-each 中使用什么节点集?

如何让内部的“for-each”正确循环日期?

我不只是想让它发挥作用,还要了解它应该如何工作。谢谢。

【问题讨论】:

  • 网上充斥着对孟池分组的解释,建议大家学习the one by Jeni Tennison。
  • 谢谢,我昨天已经读过了。只是没有完全理解。看看你下面的答案。谢谢。
  • 其实下面的答案是Martin Honnen写的,不是我写的。只是说。

标签: xml xslt


【解决方案1】:

如果您不熟悉 Muenchian 分组并且不理解这个概念,那么我认为使用嵌套分组和两个键开始一个项目不是一个好主意。至于你理解谓词generate-id(.)=generate-id(key('keyInsptr',INSPTR)[1])的问题,它只是确保for-each根据键值处理每个组中的第一项,因为表达式key('keyInsptr',INSPTR)找到相同键值的所有项目,位置谓词key('keyInsptr',INSPTR)[1] 采用这些项目中的第一个,而生成ID 检查只是比较两个节点身份的XSLT/XPath 1.0 方式(对于XPath 2.0,您可以只写[. is key('keyInsptr',INSPTR)[1]],尽管您将使用for-each-group )。因此

  <xsl:for-each select="ObjList/AS400_ELVPINS00[generate-id(.)=generate-id(key('keyInsptr', INSPTR)[1])]">

处理每个组中具有相同键值的第一个AS400_ELVPINS00(按文档顺序)。

现在要扩展分组,您通常使用分隔符连接键值,而不是预期的键值,因此使用

  <xsl:key name="keyDate" match="ObjList/AS400_ELVPINS00" use="concat(INSPTR, '|', ELVINSP_DT)" />

和

    <xsl:for-each select="key('keyInsptr', INSPTR)[generate-id(.)=generate-id(key('keyDate', concat(INSPTR, '|', ELVINSP_DT))[1])]">
      <fo:block>
        <xsl:text> - </xsl:text>
        <xsl:call-template name="dateFormat">
          <xsl:with-param name="value" select="ELVINSP_DT" />
        </xsl:call-template>
      </fo:block>
    </xsl:for-each>

您将实施第二级分组。

【讨论】:

  • 好的,所以对于我的示例数据,key('keyInsptr',INSPTR) 会给我/返回/包含两组 ObjList/AS400_ELVPINS00 对象,对吗?
  • 我理解为第二个分组有一个密钥对,这是有道理的。但是,我现在收到此消息:表达式必须评估为节点集。 ...PTR)[generate-id(.)=generate-id(-->concat(INSPTR, '|', ELVINSP_DT)
  • 关键函数调用在谓词内,因此它是相对于选定的AS400_ELVPINS00 元素完成的。 select select="ObjList/AS400_ELVPINS00" 选择所有AS400_ELVPINS00 元素,然后谓词根据条件过滤它们;在这种情况下,键调用key('keyInsptr',INSPTR) 计算具有相同键值(具有相同INSPTR 值)的所有项目的节点集,位置谓词[1] 采用其中的第一个,并且生成ID 检查使确保 for-each 只为每个组处理一个项目,即每个组中的第一个。
  • 想通了。需要正确使用密钥:
  • 是的,很抱歉,嵌套谓词缺少键函数调用,我刚刚写了键值计算。现已更正。
猜你喜欢
  • 2019-12-07
  • 2018-03-28
  • 2021-11-20
  • 2022-11-11
  • 2015-04-10
  • 2015-07-30
  • 1970-01-01
  • 2014-02-06
  • 1970-01-01
相关资源
最近更新 更多